@rubytech/create-maxy-code 0.1.45 → 0.1.49
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/__tests__/premium-mcp-discover.test.js +85 -0
- package/dist/index.js +25 -16
- package/dist/lib/premium-mcp-discover.js +34 -0
- package/package.json +1 -1
- package/payload/platform/lib/admins-write/dist/index.d.ts +0 -1
- package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admins-write/dist/index.js +2 -5
- package/payload/platform/lib/admins-write/dist/index.js.map +1 -1
- package/payload/platform/lib/admins-write/src/index.ts +2 -8
- package/payload/platform/lib/graph-mcp/dist/index.js +1 -4
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +7 -6
- package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -1
- package/payload/platform/lib/graph-mcp/dist/schema-cache.js +7 -6
- package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +1 -4
- package/payload/platform/lib/graph-mcp/src/schema-cache.ts +7 -6
- package/payload/platform/lib/graph-search/dist/index.d.ts +5 -5
- package/payload/platform/lib/graph-search/dist/index.js +4 -4
- package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +6 -7
- package/payload/platform/lib/graph-search/src/index.ts +5 -5
- package/payload/platform/lib/graph-trash/dist/index.d.ts +8 -12
- package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-trash/dist/index.js +8 -12
- package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-trash/src/index.ts +8 -12
- package/payload/platform/lib/graph-write/dist/index.d.ts +8 -9
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +9 -10
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/index.ts +9 -10
- package/payload/platform/lib/mcp-eager/dist/index.d.ts +4 -4
- package/payload/platform/lib/mcp-eager/dist/index.js +4 -4
- package/payload/platform/lib/mcp-eager/src/index.ts +4 -4
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +56 -38
- package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +42 -40
- package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +2 -2
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +7 -9
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +10 -12
- package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +3 -3
- package/payload/platform/plugins/docs/references/deployment.md +2 -14
- package/payload/platform/plugins/docs/references/platform.md +2 -2
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +5 -5
- package/payload/platform/plugins/loop/PLUGIN.md +67 -12
- package/payload/platform/plugins/loop/mcp/dist/index.js +42 -16
- package/payload/platform/plugins/loop/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
- package/payload/platform/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
- package/payload/platform/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
- package/payload/platform/plugins/loop/mcp/src/index.ts +68 -17
- package/payload/platform/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
- package/payload/platform/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
- package/payload/platform/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
- package/payload/platform/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
- package/payload/platform/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +4 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +7 -12
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +4 -4
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js.map +1 -1
- package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.d.ts.map +1 -1
- package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js +8 -9
- package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +2 -2
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +2 -2
- package/payload/platform/scripts/admin-persist-audit.ts +4 -10
- package/payload/platform/scripts/conversation-id-allowlist.txt +0 -1
- package/payload/platform/scripts/lib/resolve-account-dir.sh +0 -2
- package/payload/platform/scripts/resume-tunnel.sh +2 -9
- package/payload/platform/scripts/seed-neo4j.sh +26 -104
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +53 -7
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +0 -5
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +13 -17
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +10 -2
- package/payload/platform/templates/agents/admin/SOUL.md +23 -1
- package/payload/premium-plugins/real-agent/agents/buyer-enquiry/SOUL.md +10 -0
- package/payload/premium-plugins/real-agent/agents/compliance.md +1 -1
- package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
- package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/PLUGIN.md +67 -12
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js +42 -16
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/index.ts +68 -17
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
- package/payload/server/public/assets/admin-DBuCWSPS.js +216 -0
- package/payload/server/public/assets/{data-BxpOR0eM.js → data-BeblX4m4.js} +1 -1
- package/payload/server/public/assets/{graph-CrmxRSeb.js → graph-ZuBiYril.js} +1 -1
- package/payload/server/public/assets/graph-labels-CnbJR6cp.js +1 -0
- package/payload/server/public/assets/page-DDyny08O.js +50 -0
- package/payload/server/public/assets/page-nAY64ID7.js +1 -0
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +4 -4
- package/payload/server/server.js +9 -46
- package/payload/platform/plugins/docs/references/migration-guide.md +0 -90
- package/payload/platform/plugins/loop/mcp/src/tools/property-request.ts +0 -42
- package/payload/platform/scripts/component-knowledgedoc-backfill.ts +0 -214
- package/payload/platform/scripts/migrate-import.sh +0 -437
- package/payload/platform/scripts/taskmaster-export.sh +0 -388
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-request.ts +0 -42
- package/payload/server/public/assets/admin-DVZcLuYu.js +0 -216
- package/payload/server/public/assets/graph-labels-C8A6BmtP.js +0 -1
- package/payload/server/public/assets/page-D5wAeFU0.js +0 -50
- package/payload/server/public/assets/page-DR5NU6S0.js +0 -1
|
@@ -1,41 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loopPost, withTeamKey } from "../lib/loop-api.js";
|
|
2
2
|
export async function marketingEnquiry(params) {
|
|
3
|
-
const { accountId, teamName,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return loopPost(apiKey, "/marketing/enquiries/seller", params.sellerEnquiryData ?? {}, "loop-marketing-enquiry", teamName);
|
|
7
|
-
});
|
|
8
|
-
return `Seller enquiry submitted via team "${teamName}".`;
|
|
9
|
-
}
|
|
10
|
-
if (!params.autoResponderId || !params.autoResponderKey) {
|
|
11
|
-
throw new Error("autoResponderId and autoResponderKey are required for autoresponder actions.");
|
|
12
|
-
}
|
|
13
|
-
const id = params.autoResponderId;
|
|
14
|
-
const key = params.autoResponderKey;
|
|
15
|
-
if (action === "autoresponder-get") {
|
|
16
|
-
const result = await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
|
|
17
|
-
return loopGet(apiKey, `/marketing/enquiries/auto-responder/${id}/${key}`, "loop-marketing-enquiry", teamName);
|
|
18
|
-
});
|
|
19
|
-
return JSON.stringify(result, null, 2);
|
|
20
|
-
}
|
|
21
|
-
if (action === "autoresponder-answers") {
|
|
22
|
-
await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
|
|
23
|
-
return loopPut(apiKey, `/marketing/enquiries/auto-responder/${id}/answers/${key}`, params.answers ?? [], "loop-marketing-enquiry", teamName);
|
|
24
|
-
});
|
|
25
|
-
return `Auto-responder answers submitted for enquiry ${id} via team "${teamName}".`;
|
|
26
|
-
}
|
|
27
|
-
if (action === "autoresponder-details") {
|
|
28
|
-
await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
|
|
29
|
-
return loopPut(apiKey, `/marketing/enquiries/auto-responder/${id}/details/${key}`, params.details ?? {}, "loop-marketing-enquiry", teamName);
|
|
30
|
-
});
|
|
31
|
-
return `Auto-responder details updated for enquiry ${id} via team "${teamName}".`;
|
|
32
|
-
}
|
|
33
|
-
if (action === "autoresponder-refer") {
|
|
34
|
-
await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
|
|
35
|
-
return loopPut(apiKey, `/marketing/enquiries/auto-responder/${id}/refer/${key}`, {}, "loop-marketing-enquiry", teamName);
|
|
36
|
-
});
|
|
37
|
-
return `Enquiry ${id} referred via team "${teamName}".`;
|
|
38
|
-
}
|
|
39
|
-
throw new Error(`Unknown action: ${action}`);
|
|
3
|
+
const { accountId, teamName, sellerEnquiryData } = params;
|
|
4
|
+
await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => loopPost(apiKey, "/marketing/enquiries/seller", sellerEnquiryData ?? {}, "loop-marketing-enquiry", teamName));
|
|
5
|
+
return `Seller enquiry submitted via team "${teamName}".`;
|
|
40
6
|
}
|
|
41
7
|
//# sourceMappingURL=marketing-enquiry.js.map
|
package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marketing-enquiry.js","sourceRoot":"","sources":["../../src/tools/marketing-enquiry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"marketing-enquiry.js","sourceRoot":"","sources":["../../src/tools/marketing-enquiry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAY3D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAItC;IACC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAAC;IAC1D,MAAM,WAAW,CACf,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAC1D,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,QAAQ,CACxB,MAAM,EAAE,6BAA6B,EACrC,iBAAiB,IAAI,EAAE,EAAE,wBAAwB,EAAE,QAAQ,CAC5D,CACF,CAAC;IACF,OAAO,sCAAsC,QAAQ,IAAI,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type Department = "sales" | "lettings";
|
|
2
|
+
export declare function propertyViewing(params: {
|
|
3
|
+
accountId: string;
|
|
4
|
+
teamName: string;
|
|
5
|
+
propertyId: number;
|
|
6
|
+
department: Department;
|
|
7
|
+
name?: string;
|
|
8
|
+
email?: string;
|
|
9
|
+
phone?: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
}): Promise<string>;
|
|
12
|
+
export declare function propertyCallback(params: {
|
|
13
|
+
accountId: string;
|
|
14
|
+
teamName: string;
|
|
15
|
+
propertyId: number;
|
|
16
|
+
department: Department;
|
|
17
|
+
name?: string;
|
|
18
|
+
email?: string;
|
|
19
|
+
phone?: string;
|
|
20
|
+
message?: string;
|
|
21
|
+
}): Promise<string>;
|
|
22
|
+
export declare function propertyInformation(params: {
|
|
23
|
+
accountId: string;
|
|
24
|
+
teamName: string;
|
|
25
|
+
propertyId: number;
|
|
26
|
+
department: Department;
|
|
27
|
+
name?: string;
|
|
28
|
+
email?: string;
|
|
29
|
+
phone?: string;
|
|
30
|
+
message?: string;
|
|
31
|
+
}): Promise<string>;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=property-intent.d.ts.map
|
package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-intent.d.ts","sourceRoot":"","sources":["../../src/tools/property-intent.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AA4CvC,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAElB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAElB;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAElB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { loopPost, withTeamKey } from "../lib/loop-api.js";
|
|
2
|
+
async function submitIntent(toolName, action, params, successLabel) {
|
|
3
|
+
const { accountId, teamName, propertyId, department, ...body } = params;
|
|
4
|
+
await withTeamKey(accountId, teamName, "properties", toolName, async (apiKey) => {
|
|
5
|
+
const path = `/property/residential/${department}/${propertyId}/${action}`;
|
|
6
|
+
return loopPost(apiKey, path, body, toolName, teamName);
|
|
7
|
+
});
|
|
8
|
+
return `${successLabel} submitted for property ${propertyId} (${department}) via team "${teamName}".`;
|
|
9
|
+
}
|
|
10
|
+
export async function propertyViewing(params) {
|
|
11
|
+
return submitIntent("loop-property-viewing", "viewing", params, "Viewing request");
|
|
12
|
+
}
|
|
13
|
+
export async function propertyCallback(params) {
|
|
14
|
+
return submitIntent("loop-property-callback", "call-back", params, "Callback request");
|
|
15
|
+
}
|
|
16
|
+
export async function propertyInformation(params) {
|
|
17
|
+
return submitIntent("loop-property-information", "information", params, "Information request");
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=property-intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-intent.js","sourceRoot":"","sources":["../../src/tools/property-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAiB3D,KAAK,UAAU,YAAY,CACzB,QAAgB,EAChB,MAA+C,EAC/C,MASC,EACD,YAAoB;IAEpB,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IACxE,MAAM,WAAW,CACf,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,yBAAyB,UAAU,IAAI,UAAU,IAAI,MAAM,EAAE,CAAC;QAC3E,OAAO,QAAQ,CAAsB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/E,CAAC,CACF,CAAC;IACF,OAAO,GAAG,YAAY,2BAA2B,UAAU,KAAK,UAAU,eAAe,QAAQ,IAAI,CAAC;AACxG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MASrC;IACC,OAAO,YAAY,CAAC,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAStC;IACC,OAAO,YAAY,CAAC,wBAAwB,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MASzC;IACC,OAAO,YAAY,CAAC,2BAA2B,EAAE,aAAa,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC;AACjG,CAAC"}
|
package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"property-listed.d.ts","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAkCA,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAChD,KAAK,OAAO,GAAG,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElE,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,
|
|
1
|
+
{"version":3,"file":"property-listed.d.ts","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAkCA,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAChD,KAAK,OAAO,GAAG,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElE,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqClB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { aggregateAcrossTeams, formatAggregationResult, loopGet, } from "../lib/loop-api.js";
|
|
2
2
|
export async function propertyListed(params) {
|
|
3
|
-
const { accountId, channel, department = "both",
|
|
3
|
+
const { accountId, channel, department = "both", teamName, limit } = params;
|
|
4
4
|
const result = await aggregateAcrossTeams(accountId, "properties", "loop-property-listed", async (apiKey, team) => {
|
|
5
5
|
const all = [];
|
|
6
6
|
const depts = department === "both" ? ["sales", "lettings"] : [department];
|
|
@@ -10,12 +10,6 @@ export async function propertyListed(params) {
|
|
|
10
10
|
if (Array.isArray(data))
|
|
11
11
|
all.push(...data);
|
|
12
12
|
}
|
|
13
|
-
if (includeSold) {
|
|
14
|
-
const soldPath = `/property/residential/sold/${channel}`;
|
|
15
|
-
const soldData = await loopGet(apiKey, soldPath, "loop-property-listed", team);
|
|
16
|
-
if (Array.isArray(soldData))
|
|
17
|
-
all.push(...soldData);
|
|
18
|
-
}
|
|
19
13
|
return all;
|
|
20
14
|
}, { teamName, limitPerTeam: limit ?? 50, limitTotal: limit ?? 200 });
|
|
21
15
|
return formatAggregationResult(result, (p) => {
|
package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"property-listed.js","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,OAAO,GACR,MAAM,oBAAoB,CAAC;AAiC5B,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"property-listed.js","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,OAAO,GACR,MAAM,oBAAoB,CAAC;AAiC5B,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAMpC;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAE5E,MAAM,MAAM,GAAG,MAAM,oBAAoB,CACvC,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,GAAG,GAA0B,EAAE,CAAC;QACtC,MAAM,KAAK,GACT,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAE/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,yBAAyB,IAAI,WAAW,OAAO,EAAE,CAAC;YAC/D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAwB,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAC;YAC9F,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,CAClE,CAAC;IAEF,OAAO,uBAAuB,CAC5B,MAAM,EACN,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,IAAI,GAAG,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,eAAe,IAAI,iBAAiB,CAAC;QACxE,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtG,OAAO,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;IACtE,CAAC,EACD,GAAG,OAAO,WAAW,CACtB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Channel = "rightmove" | "onTheMarket" | "zoopla" | "website";
|
|
2
|
+
export declare function propertySold(params: {
|
|
3
|
+
accountId: string;
|
|
4
|
+
channel: Channel;
|
|
5
|
+
teamName?: string;
|
|
6
|
+
limit?: number;
|
|
7
|
+
}): Promise<string>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=property-sold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-sold.d.ts","sourceRoot":"","sources":["../../src/tools/property-sold.ts"],"names":[],"mappings":"AA+BA,KAAK,OAAO,GAAG,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElE,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BlB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { aggregateAcrossTeams, formatAggregationResult, loopGet, } from "../lib/loop-api.js";
|
|
2
|
+
export async function propertySold(params) {
|
|
3
|
+
const { accountId, channel, teamName, limit } = params;
|
|
4
|
+
const result = await aggregateAcrossTeams(accountId, "properties", "loop-property-sold", async (apiKey, team) => {
|
|
5
|
+
const path = `/property/residential/sold/${channel}`;
|
|
6
|
+
const data = await loopGet(apiKey, path, "loop-property-sold", team);
|
|
7
|
+
return Array.isArray(data) ? data : [];
|
|
8
|
+
}, { teamName, limitPerTeam: limit ?? 50, limitTotal: limit ?? 200 });
|
|
9
|
+
return formatAggregationResult(result, (p) => {
|
|
10
|
+
const addr = p.displayAddress ?? p.propertyAddress ?? "Unknown address";
|
|
11
|
+
const id = p.propertyId != null ? ` [ID: ${p.propertyId}]` : "";
|
|
12
|
+
const price = p.price ? ` — £${p.price.toLocaleString("en-GB")}` : "";
|
|
13
|
+
const beds = p.bedrooms ? ` ${p.bedrooms}bed` : "";
|
|
14
|
+
const propType = p.propertyType ? ` (${p.propertyType})` : "";
|
|
15
|
+
const status = p.status ? ` [${p.status}]` : "";
|
|
16
|
+
return `- ${addr}${id}${price}${beds}${propType}${status}`;
|
|
17
|
+
}, `${channel} sold`);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=property-sold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-sold.js","sourceRoot":"","sources":["../../src/tools/property-sold.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,OAAO,GACR,MAAM,oBAAoB,CAAC;AA6B5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAKlC;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAEvD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CACvC,SAAS,EACT,YAAY,EACZ,oBAAoB,EACpB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,IAAI,GAAG,8BAA8B,OAAO,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAwB,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,CAAC,CAAC;QAC5F,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,CAAC,EACD,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,CAClE,CAAC;IAEF,OAAO,uBAAuB,CAC5B,MAAM,EACN,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,IAAI,GAAG,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,eAAe,IAAI,iBAAiB,CAAC;QACxE,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,OAAO,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,EAAE,CAAC;IAC7D,CAAC,EACD,GAAG,OAAO,OAAO,CAClB,CAAC;AACJ,CAAC"}
|
package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task 103: per-tool shape tests for the three new value-pillar tools
|
|
3
|
+
* (loop-auto-responder, loop-property-sold, and the split property-intent
|
|
4
|
+
* tools). Asserts that each tool source references the swagger path family
|
|
5
|
+
* it claims to cover, and that index.ts registers it with the correct name.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { resolve, dirname } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const PLUGIN_SRC = resolve(__dirname, '..');
|
|
15
|
+
const SWAGGER = JSON.parse(
|
|
16
|
+
readFileSync(resolve(__dirname, 'loop-swagger.snapshot.json'), 'utf-8'),
|
|
17
|
+
) as { paths: Record<string, Record<string, unknown>> };
|
|
18
|
+
|
|
19
|
+
const indexSrc = readFileSync(resolve(PLUGIN_SRC, 'index.ts'), 'utf-8');
|
|
20
|
+
const readSrc = (rel: string) =>
|
|
21
|
+
readFileSync(resolve(PLUGIN_SRC, rel), 'utf-8');
|
|
22
|
+
|
|
23
|
+
interface ToolSpec {
|
|
24
|
+
tool: string;
|
|
25
|
+
source: string;
|
|
26
|
+
// `sourceFragment` is the literal substring the source file must contain —
|
|
27
|
+
// typically the stable prefix before a `${}` template variable.
|
|
28
|
+
sourceFragment: string;
|
|
29
|
+
swaggerPaths: { method: 'get' | 'post' | 'put'; path: string }[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const NEW_TOOLS: ToolSpec[] = [
|
|
33
|
+
{
|
|
34
|
+
tool: 'loop-auto-responder',
|
|
35
|
+
source: 'tools/auto-responder.ts',
|
|
36
|
+
sourceFragment: '/marketing/enquiries/auto-responder/',
|
|
37
|
+
swaggerPaths: [
|
|
38
|
+
{ method: 'get', path: '/marketing/enquiries/auto-responder/{id}/{key}' },
|
|
39
|
+
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/answers/{key}' },
|
|
40
|
+
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/details/{key}' },
|
|
41
|
+
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/refer/{key}' },
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
tool: 'loop-property-sold',
|
|
46
|
+
source: 'tools/property-sold.ts',
|
|
47
|
+
sourceFragment: '/property/residential/sold/',
|
|
48
|
+
swaggerPaths: [
|
|
49
|
+
{ method: 'get', path: '/property/residential/sold/{channel}' },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
tool: 'loop-property-viewing',
|
|
54
|
+
source: 'tools/property-intent.ts',
|
|
55
|
+
sourceFragment: '/property/residential/',
|
|
56
|
+
swaggerPaths: [
|
|
57
|
+
{ method: 'post', path: '/property/residential/sales/{id}/viewing' },
|
|
58
|
+
{ method: 'post', path: '/property/residential/lettings/{id}/viewing' },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
tool: 'loop-property-callback',
|
|
63
|
+
source: 'tools/property-intent.ts',
|
|
64
|
+
sourceFragment: '/property/residential/',
|
|
65
|
+
swaggerPaths: [
|
|
66
|
+
{ method: 'post', path: '/property/residential/sales/{id}/call-back' },
|
|
67
|
+
{ method: 'post', path: '/property/residential/lettings/{id}/call-back' },
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
tool: 'loop-property-information',
|
|
72
|
+
source: 'tools/property-intent.ts',
|
|
73
|
+
sourceFragment: '/property/residential/',
|
|
74
|
+
swaggerPaths: [
|
|
75
|
+
{ method: 'post', path: '/property/residential/sales/{id}/information' },
|
|
76
|
+
{ method: 'post', path: '/property/residential/lettings/{id}/information' },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
describe('Task 103 new tools', () => {
|
|
82
|
+
it.each(NEW_TOOLS)('$tool is registered in index.ts', ({ tool }) => {
|
|
83
|
+
const re = new RegExp(`server\\.tool\\(\\s*"${tool}"`);
|
|
84
|
+
expect(re.test(indexSrc), `tool ${tool} missing from index.ts`).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it.each(NEW_TOOLS)('$tool source file references the swagger path family', ({ source, sourceFragment }) => {
|
|
88
|
+
const src = readSrc(source);
|
|
89
|
+
expect(src.includes(sourceFragment), `${source} missing literal "${sourceFragment}"`).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it.each(NEW_TOOLS)('$tool swagger paths exist in the snapshot', ({ swaggerPaths }) => {
|
|
93
|
+
for (const { method, path } of swaggerPaths) {
|
|
94
|
+
const op = SWAGGER.paths[path];
|
|
95
|
+
expect(op, `path ${path} missing from swagger snapshot`).toBeDefined();
|
|
96
|
+
expect(op[method], `${method.toUpperCase()} ${path} missing from swagger snapshot`).toBeDefined();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -58,18 +58,19 @@ const ENDPOINT_MAP: EndpointMapping[] = [
|
|
|
58
58
|
{ method: 'post', path: '/marketing/rentals/matching/{id}/information', tool: 'loop-marketing-match-request', source: 'tools/marketing-match-request.ts', fragment: '/marketing/rentals' },
|
|
59
59
|
{ method: 'post', path: '/marketing/matching/{id}/callback', tool: 'loop-marketing-match-request', source: 'tools/marketing-match-request.ts', fragment: '/matching/' },
|
|
60
60
|
{ method: 'post', path: '/marketing/rentals/matching/{id}/callback', tool: 'loop-marketing-match-request', source: 'tools/marketing-match-request.ts', fragment: '/marketing/rentals' },
|
|
61
|
-
// Marketing —
|
|
61
|
+
// Marketing — seller enquiry (1)
|
|
62
62
|
{ method: 'post', path: '/marketing/enquiries/seller', tool: 'loop-marketing-enquiry', source: 'tools/marketing-enquiry.ts', fragment: '/marketing/enquiries/seller' },
|
|
63
|
-
|
|
64
|
-
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/
|
|
65
|
-
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{ method: 'post', path: '/property/residential/sales/{id}/
|
|
69
|
-
{ method: 'post', path: '/property/residential/sales/{id}/
|
|
70
|
-
{ method: 'post', path: '/property/residential/
|
|
71
|
-
{ method: 'post', path: '/property/residential/lettings/{id}/
|
|
72
|
-
{ method: 'post', path: '/property/residential/lettings/{id}/
|
|
63
|
+
// Marketing — auto-responder (3) — Task 103 split into loop-auto-responder
|
|
64
|
+
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/answers/{key}', tool: 'loop-auto-responder', source: 'tools/auto-responder.ts', fragment: '/marketing/enquiries/auto-responder/' },
|
|
65
|
+
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/details/{key}', tool: 'loop-auto-responder', source: 'tools/auto-responder.ts', fragment: '/marketing/enquiries/auto-responder/' },
|
|
66
|
+
{ method: 'put', path: '/marketing/enquiries/auto-responder/{id}/refer/{key}', tool: 'loop-auto-responder', source: 'tools/auto-responder.ts', fragment: '/marketing/enquiries/auto-responder/' },
|
|
67
|
+
// Property intent (6) — Task 103 split loop-property-request into three intent-clear tools
|
|
68
|
+
{ method: 'post', path: '/property/residential/sales/{id}/viewing', tool: 'loop-property-viewing', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
|
|
69
|
+
{ method: 'post', path: '/property/residential/sales/{id}/call-back', tool: 'loop-property-callback', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
|
|
70
|
+
{ method: 'post', path: '/property/residential/sales/{id}/information', tool: 'loop-property-information', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
|
|
71
|
+
{ method: 'post', path: '/property/residential/lettings/{id}/viewing', tool: 'loop-property-viewing', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
|
|
72
|
+
{ method: 'post', path: '/property/residential/lettings/{id}/call-back', tool: 'loop-property-callback', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
|
|
73
|
+
{ method: 'post', path: '/property/residential/lettings/{id}/information', tool: 'loop-property-information', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
|
|
73
74
|
// Supplier (3)
|
|
74
75
|
{ method: 'post', path: '/supplier/maintenance/{code}/{jobid}/complete', tool: 'loop-supplier', source: 'tools/supplier.ts', fragment: '/supplier/maintenance/' },
|
|
75
76
|
{ method: 'put', path: '/supplier/maintenance/{code}/{quoteid}/quote-for-job', tool: 'loop-supplier', source: 'tools/supplier.ts', fragment: '/quote-for-job' },
|
|
@@ -10,7 +10,8 @@ import { keyList } from "./tools/key-list.js";
|
|
|
10
10
|
import { propertySearch } from "./tools/property-search.js";
|
|
11
11
|
import { propertyDetail } from "./tools/property-detail.js";
|
|
12
12
|
import { propertyListed } from "./tools/property-listed.js";
|
|
13
|
-
import {
|
|
13
|
+
import { propertySold } from "./tools/property-sold.js";
|
|
14
|
+
import { propertyViewing, propertyCallback, propertyInformation } from "./tools/property-intent.js";
|
|
14
15
|
import { peopleSearch } from "./tools/people-search.js";
|
|
15
16
|
import { peopleDetail } from "./tools/people-detail.js";
|
|
16
17
|
import { viewingSearch } from "./tools/viewing-search.js";
|
|
@@ -24,6 +25,7 @@ import { marketingMatchDetail } from "./tools/marketing-match.js";
|
|
|
24
25
|
import { marketingMatchBatch } from "./tools/marketing-match-batch.js";
|
|
25
26
|
import { marketingMatchRequest } from "./tools/marketing-match-request.js";
|
|
26
27
|
import { marketingEnquiry } from "./tools/marketing-enquiry.js";
|
|
28
|
+
import { autoResponder } from "./tools/auto-responder.js";
|
|
27
29
|
import { customerPreferences } from "./tools/customer-preferences.js";
|
|
28
30
|
import { supplier } from "./tools/supplier.js";
|
|
29
31
|
import { closeDriver } from "./lib/neo4j.js";
|
|
@@ -194,11 +196,10 @@ server.tool(
|
|
|
194
196
|
|
|
195
197
|
server.tool(
|
|
196
198
|
"loop-property-listed",
|
|
197
|
-
"Get properties listed on a specific channel (Rightmove, Zoopla, OnTheMarket, website).
|
|
199
|
+
"Get properties currently listed on a specific channel (Rightmove, Zoopla, OnTheMarket, website). For exchanged/completed properties use loop-property-sold.",
|
|
198
200
|
{
|
|
199
201
|
channel: z.enum(["rightmove", "onTheMarket", "zoopla", "website"]).describe("Listing channel"),
|
|
200
202
|
department: z.enum(["sales", "lettings", "both"]).optional().describe("Department (default: both)"),
|
|
201
|
-
includeSold: z.boolean().optional().describe("Include sold gallery (default: false)"),
|
|
202
203
|
teamName: z.string().optional().describe("Query a specific team only"),
|
|
203
204
|
limit: z.number().int().optional().describe("Max results (default 200)"),
|
|
204
205
|
},
|
|
@@ -206,19 +207,63 @@ server.tool(
|
|
|
206
207
|
);
|
|
207
208
|
|
|
208
209
|
server.tool(
|
|
209
|
-
"loop-property-
|
|
210
|
-
"
|
|
210
|
+
"loop-property-sold",
|
|
211
|
+
"Get exchanged or completed properties on a specific channel. Powers canvassing from recent sales and sold-gallery rendering.",
|
|
212
|
+
{
|
|
213
|
+
channel: z.enum(["rightmove", "onTheMarket", "zoopla", "website"]).describe("Listing channel"),
|
|
214
|
+
teamName: z.string().optional().describe("Query a specific team only"),
|
|
215
|
+
limit: z.number().int().optional().describe("Max results (default 200)"),
|
|
216
|
+
},
|
|
217
|
+
toolHandler(async (p) => propertySold(p as Parameters<typeof propertySold>[0]))
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Property-level intent tools (Task 103 split — replaces loop-property-request).
|
|
221
|
+
// Each intent is a distinct operator action so the agent's tool surface
|
|
222
|
+
// preserves intent fidelity.
|
|
223
|
+
|
|
224
|
+
server.tool(
|
|
225
|
+
"loop-property-viewing",
|
|
226
|
+
"Request a viewing for a property. Use when the operator says 'book a viewing', 'arrange a viewing', or 'ask to see the property'.",
|
|
227
|
+
{
|
|
228
|
+
teamName: z.string().min(1).describe("Team to submit the request through"),
|
|
229
|
+
propertyId: z.number().int().describe("Property ID"),
|
|
230
|
+
department: z.enum(["sales", "lettings"]).describe("sales or lettings"),
|
|
231
|
+
name: z.string().optional().describe("Requester name"),
|
|
232
|
+
email: z.string().optional().describe("Requester email"),
|
|
233
|
+
phone: z.string().optional().describe("Requester phone"),
|
|
234
|
+
message: z.string().optional().describe("Additional message"),
|
|
235
|
+
},
|
|
236
|
+
toolHandler(async (p) => propertyViewing(p as Parameters<typeof propertyViewing>[0]))
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
server.tool(
|
|
240
|
+
"loop-property-callback",
|
|
241
|
+
"Request a callback about a property. Use when the operator says 'ask them to call', 'request a callback', or 'have someone ring back'.",
|
|
242
|
+
{
|
|
243
|
+
teamName: z.string().min(1).describe("Team to submit the request through"),
|
|
244
|
+
propertyId: z.number().int().describe("Property ID"),
|
|
245
|
+
department: z.enum(["sales", "lettings"]).describe("sales or lettings"),
|
|
246
|
+
name: z.string().optional().describe("Requester name"),
|
|
247
|
+
email: z.string().optional().describe("Requester email"),
|
|
248
|
+
phone: z.string().optional().describe("Requester phone"),
|
|
249
|
+
message: z.string().optional().describe("Additional message"),
|
|
250
|
+
},
|
|
251
|
+
toolHandler(async (p) => propertyCallback(p as Parameters<typeof propertyCallback>[0]))
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
server.tool(
|
|
255
|
+
"loop-property-information",
|
|
256
|
+
"Request more information about a property. Use when the operator says 'ask for details', 'request the brochure', or 'find out more'.",
|
|
211
257
|
{
|
|
212
258
|
teamName: z.string().min(1).describe("Team to submit the request through"),
|
|
213
259
|
propertyId: z.number().int().describe("Property ID"),
|
|
214
260
|
department: z.enum(["sales", "lettings"]).describe("sales or lettings"),
|
|
215
|
-
action: z.enum(["viewing", "call-back", "information"]).describe("Request type"),
|
|
216
261
|
name: z.string().optional().describe("Requester name"),
|
|
217
262
|
email: z.string().optional().describe("Requester email"),
|
|
218
263
|
phone: z.string().optional().describe("Requester phone"),
|
|
219
264
|
message: z.string().optional().describe("Additional message"),
|
|
220
265
|
},
|
|
221
|
-
toolHandler(async (p) =>
|
|
266
|
+
toolHandler(async (p) => propertyInformation(p as Parameters<typeof propertyInformation>[0]))
|
|
222
267
|
);
|
|
223
268
|
|
|
224
269
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -377,22 +422,28 @@ server.tool(
|
|
|
377
422
|
|
|
378
423
|
server.tool(
|
|
379
424
|
"loop-marketing-enquiry",
|
|
380
|
-
"
|
|
425
|
+
"Submit a seller-side marketing enquiry to Loop. For inbound applicant auto-responder workflows use loop-auto-responder.",
|
|
381
426
|
{
|
|
382
427
|
teamName: z.string().min(1).describe("Team to submit through"),
|
|
383
|
-
|
|
384
|
-
"seller-enquiry", "autoresponder-get", "autoresponder-answers",
|
|
385
|
-
"autoresponder-details", "autoresponder-refer",
|
|
386
|
-
]).describe("Enquiry action"),
|
|
387
|
-
sellerEnquiryData: z.record(z.string(), z.unknown()).optional().describe("Seller enquiry request body (for seller-enquiry)"),
|
|
388
|
-
autoResponderId: z.number().int().optional().describe("Auto-responder enquiry ID"),
|
|
389
|
-
autoResponderKey: z.string().optional().describe("Auto-responder key (UUID)"),
|
|
390
|
-
answers: z.array(z.unknown()).optional().describe("Auto-responder answers array"),
|
|
391
|
-
details: z.record(z.string(), z.unknown()).optional().describe("Auto-responder details object"),
|
|
428
|
+
sellerEnquiryData: z.record(z.string(), z.unknown()).optional().describe("Seller enquiry request body"),
|
|
392
429
|
},
|
|
393
430
|
toolHandler(async (p) => marketingEnquiry(p as Parameters<typeof marketingEnquiry>[0]))
|
|
394
431
|
);
|
|
395
432
|
|
|
433
|
+
server.tool(
|
|
434
|
+
"loop-auto-responder",
|
|
435
|
+
"Read or progress an inbound enquiry through Loop's auto-responder (the surface behind Loop's 40% enquiry-efficiency claim). action=get reads questions+details; answers submits applicant replies; details updates the enquiry record; refer hands it to another team.",
|
|
436
|
+
{
|
|
437
|
+
teamName: z.string().min(1).describe("Team for this operation"),
|
|
438
|
+
action: z.enum(["get", "answers", "details", "refer"]).describe("Auto-responder action"),
|
|
439
|
+
autoResponderId: z.number().int().describe("Auto-responder enquiry ID"),
|
|
440
|
+
autoResponderKey: z.string().describe("Auto-responder key (UUID issued at enquiry creation)"),
|
|
441
|
+
answers: z.array(z.unknown()).optional().describe("Applicant answers (required for action=answers)"),
|
|
442
|
+
details: z.record(z.string(), z.unknown()).optional().describe("Enquiry details (for action=details)"),
|
|
443
|
+
},
|
|
444
|
+
toolHandler(async (p) => autoResponder(p as Parameters<typeof autoResponder>[0]))
|
|
445
|
+
);
|
|
446
|
+
|
|
396
447
|
// ─────────────────────────────────────────────────────────────────
|
|
397
448
|
// Customer Tools (1) — permission: customer
|
|
398
449
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { loopGet, loopPut, withTeamKey } from "../lib/loop-api.js";
|
|
2
|
+
|
|
3
|
+
type AutoResponderAction = "get" | "answers" | "details" | "refer";
|
|
4
|
+
|
|
5
|
+
// Loop API V2: enquiry auto-responder endpoints (Loop's stated 40% efficiency lever)
|
|
6
|
+
// GET /marketing/enquiries/auto-responder/{id}/{key} — read questions + details
|
|
7
|
+
// PUT /marketing/enquiries/auto-responder/{id}/answers/{key} — submit applicant answers
|
|
8
|
+
// PUT /marketing/enquiries/auto-responder/{id}/details/{key} — update enquiry details
|
|
9
|
+
// PUT /marketing/enquiries/auto-responder/{id}/refer/{key} — refer enquiry to another team
|
|
10
|
+
// `id` is the enquiry id, `key` is the UUID handed out at enquiry creation.
|
|
11
|
+
|
|
12
|
+
interface LoopBooleanResponse {
|
|
13
|
+
success?: boolean;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface LoopAutoResponderDetails {
|
|
18
|
+
id?: number;
|
|
19
|
+
questions?: unknown[];
|
|
20
|
+
enquiryDetails?: unknown;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function autoResponder(params: {
|
|
25
|
+
accountId: string;
|
|
26
|
+
teamName: string;
|
|
27
|
+
action: AutoResponderAction;
|
|
28
|
+
autoResponderId: number;
|
|
29
|
+
autoResponderKey: string;
|
|
30
|
+
answers?: unknown[];
|
|
31
|
+
details?: Record<string, unknown>;
|
|
32
|
+
}): Promise<string> {
|
|
33
|
+
const { accountId, teamName, action, autoResponderId: id, autoResponderKey: key } = params;
|
|
34
|
+
|
|
35
|
+
if (action === "get") {
|
|
36
|
+
const result = await withTeamKey<LoopAutoResponderDetails>(
|
|
37
|
+
accountId, teamName, "marketing", "loop-auto-responder",
|
|
38
|
+
async (apiKey) => loopGet<LoopAutoResponderDetails>(
|
|
39
|
+
apiKey, `/marketing/enquiries/auto-responder/${id}/${key}`,
|
|
40
|
+
"loop-auto-responder", teamName
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
return JSON.stringify(result, null, 2);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (action === "answers") {
|
|
47
|
+
await withTeamKey<LoopBooleanResponse>(
|
|
48
|
+
accountId, teamName, "marketing", "loop-auto-responder",
|
|
49
|
+
async (apiKey) => loopPut<LoopBooleanResponse>(
|
|
50
|
+
apiKey, `/marketing/enquiries/auto-responder/${id}/answers/${key}`,
|
|
51
|
+
params.answers ?? [], "loop-auto-responder", teamName
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
return `Auto-responder answers submitted for enquiry ${id} via team "${teamName}".`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (action === "details") {
|
|
58
|
+
await withTeamKey<LoopBooleanResponse>(
|
|
59
|
+
accountId, teamName, "marketing", "loop-auto-responder",
|
|
60
|
+
async (apiKey) => loopPut<LoopBooleanResponse>(
|
|
61
|
+
apiKey, `/marketing/enquiries/auto-responder/${id}/details/${key}`,
|
|
62
|
+
params.details ?? {}, "loop-auto-responder", teamName
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
return `Auto-responder details updated for enquiry ${id} via team "${teamName}".`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (action === "refer") {
|
|
69
|
+
await withTeamKey<LoopBooleanResponse>(
|
|
70
|
+
accountId, teamName, "marketing", "loop-auto-responder",
|
|
71
|
+
async (apiKey) => loopPut<LoopBooleanResponse>(
|
|
72
|
+
apiKey, `/marketing/enquiries/auto-responder/${id}/refer/${key}`,
|
|
73
|
+
{}, "loop-auto-responder", teamName
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
return `Enquiry ${id} referred via team "${teamName}".`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
throw new Error(`Unknown auto-responder action: ${action}`);
|
|
80
|
+
}
|