@rubytech/create-realagent 1.0.826 → 1.0.829
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/package.json +1 -1
- package/payload/platform/neo4j/schema.cypher +35 -2
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +39 -54
- package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +26 -52
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +7 -7
- package/payload/platform/plugins/docs/references/cloudflare.md +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -0
- package/payload/platform/plugins/memory/PLUGIN.md +5 -5
- package/payload/platform/plugins/memory/mcp/dist/index.js +18 -253
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +51 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +103 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts +19 -4
- 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 +149 -56
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts +16 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js +12 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +2 -138
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js +66 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js +148 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +1 -64
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +6 -336
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +30 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +231 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +21 -17
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +77 -37
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-base.md +7 -2
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +54 -4
- package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
- package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.d.ts +18 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.js +31 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.js.map +1 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.d.ts +27 -12
- package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.d.ts.map +1 -1
- package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.js +40 -20
- package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.js.map +1 -1
- package/payload/platform/plugins/whatsapp-import/lib/dist/index.d.ts +7 -4
- package/payload/platform/plugins/whatsapp-import/lib/dist/index.d.ts.map +1 -1
- package/payload/platform/plugins/whatsapp-import/lib/dist/index.js +9 -6
- package/payload/platform/plugins/whatsapp-import/lib/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.d.ts +25 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.js +48 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.js.map +1 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.d.ts +3 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.js +47 -0
- package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.js.map +1 -0
- package/payload/platform/scripts/seed-neo4j.sh +15 -14
- package/payload/platform/templates/specialists/agents/database-operator.md +10 -17
- package/payload/server/chunk-CUSH3UXP.js +2305 -0
- package/payload/server/chunk-IWNDVGKT.js +10077 -0
- package/payload/server/chunk-KC7NUABI.js +654 -0
- package/payload/server/chunk-T2OPNP3L.js +654 -0
- package/payload/server/chunk-WUVXPZIV.js +1116 -0
- package/payload/server/client-pool-3TM3SRIA.js +32 -0
- package/payload/server/cloudflare-task-tracker-4NIODMGL.js +19 -0
- package/payload/server/cloudflare-task-tracker-CR6TL4VL.js +19 -0
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/neo4j-migrations-XTQ4WEV6.js +428 -0
- package/payload/server/public/assets/{admin-DOkUspG1.js → admin-BNwPsMhJ.js} +2 -2
- package/payload/server/public/assets/{graph-LLMJa4Ch.js → graph-N_Bw-8oT.js} +1 -1
- package/payload/server/public/assets/{page-DoaF3DB0.js → page-BKLGP-th.js} +1 -1
- package/payload/server/public/graph.html +2 -2
- package/payload/server/public/index.html +2 -2
- package/payload/server/server.js +281 -168
- package/payload/platform/plugins/whatsapp-import/PLUGIN.md +0 -46
- package/payload/platform/plugins/whatsapp-import/bin/ingest.mjs +0 -670
- package/payload/platform/plugins/whatsapp-import/bin/whatsapp-ingest.sh +0 -131
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/filter-gate.test.ts +0 -172
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/ingest-idempotence.test.ts +0 -141
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/parse-export-lrm.test.ts +0 -83
- package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/parse-export.test.ts +0 -678
- package/payload/platform/plugins/whatsapp-import/lib/src/derive-keys.ts +0 -59
- package/payload/platform/plugins/whatsapp-import/lib/src/filter.ts +0 -136
- package/payload/platform/plugins/whatsapp-import/lib/src/index.ts +0 -19
- package/payload/platform/plugins/whatsapp-import/lib/src/parse-export.ts +0 -471
- package/payload/platform/plugins/whatsapp-import/lib/tsconfig.json +0 -9
- package/payload/platform/plugins/whatsapp-import/lib/vitest.config.ts +0 -9
- package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/SKILL.md +0 -131
- package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/references/export-parse.md +0 -109
- package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import-enrich/SKILL.md +0 -333
|
@@ -13,10 +13,9 @@ import { memoryReindex } from "./tools/memory-reindex.js";
|
|
|
13
13
|
import { memoryIngestExtract } from "./tools/memory-ingest-extract.js";
|
|
14
14
|
import { memoryIngest } from "./tools/memory-ingest.js";
|
|
15
15
|
import { memoryArchiveWrite } from "./tools/memory-archive-write.js";
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import { whatsappExportInsightPass } from "./tools/whatsapp-export-insight-pass.js";
|
|
16
|
+
// Task 894: WhatsApp `_chat.txt` ingestion flows through the unified
|
|
17
|
+
// document-ingest pipeline (memory-classify mode='chat' + memory-ingest
|
|
18
|
+
// parentLabel='ConversationArchive'); no WhatsApp-specific MCP tools remain.
|
|
20
19
|
import { memoryIngestWeb } from "./tools/memory-ingest-web.js";
|
|
21
20
|
import { memoryClassify } from "./tools/memory-classify.js";
|
|
22
21
|
import { memoryUpdate } from "./tools/memory-update.js";
|
|
@@ -779,50 +778,29 @@ if (!readOnly) {
|
|
|
779
778
|
};
|
|
780
779
|
}
|
|
781
780
|
});
|
|
782
|
-
server.tool("memory-archive-write", "Bulk-archive write surface (Task 744
|
|
781
|
+
server.tool("memory-archive-write", "Bulk-archive write surface (Task 744). Writes a flat dataset (typed entities + natural edges) into the graph " +
|
|
783
782
|
"in 500-row UNWIND batches. The Cypher body is fixed server-side per `archiveType`; the agent supplies parsed " +
|
|
784
|
-
"rows + the discriminant, never raw Cypher. Use ONLY for first-class entity exports (LinkedIn Connections, " +
|
|
785
|
-
"
|
|
786
|
-
"
|
|
787
|
-
"
|
|
788
|
-
"
|
|
789
|
-
"otherwise they are ignored.", {
|
|
783
|
+
"rows + the discriminant, never raw Cypher. Use ONLY for flat first-class entity exports (LinkedIn Connections, " +
|
|
784
|
+
"future CRM-type seeds). Use memory-ingest for narrative content — including WhatsApp `_chat.txt` archives, " +
|
|
785
|
+
"which are document-shaped narrative and flow through document-ingest with `parentLabel='ConversationArchive'` " +
|
|
786
|
+
"(the unified-ingest pipeline). Use memory-write for single-node operator-driven writes. " +
|
|
787
|
+
"Currently supported archiveType values: `linkedin-connections`.", {
|
|
790
788
|
archiveType: z
|
|
791
|
-
.enum(["linkedin-connections"
|
|
789
|
+
.enum(["linkedin-connections"])
|
|
792
790
|
.describe("Discriminant naming the per-source schema and Cypher body the server runs. Add a new value here only when the corresponding handler is added in memory-archive-write.ts."),
|
|
793
791
|
ownerNodeId: z
|
|
794
792
|
.string()
|
|
795
793
|
.min(1)
|
|
796
|
-
.describe("elementId of the archive owner — :AdminUser for an operator's own archive, or :Person for an external-archive owner. Confirmed during the skill's owner-confirmation flow before this tool is invoked.
|
|
794
|
+
.describe("elementId of the archive owner — :AdminUser for an operator's own archive, or :Person for an external-archive owner. Confirmed during the skill's owner-confirmation flow before this tool is invoked."),
|
|
797
795
|
rows: z
|
|
798
796
|
.array(z.record(z.string(), z.unknown()))
|
|
799
797
|
.min(1)
|
|
800
|
-
.describe("Parsed rows. The skill's selective-ingest gate runs BEFORE this tool — large blanket archives get filtered (Company / Position / Connected On range for linkedin-connections
|
|
798
|
+
.describe("Parsed rows. The skill's selective-ingest gate runs BEFORE this tool — large blanket archives get filtered (e.g. Company / Position / Connected On range for linkedin-connections) before the write call."),
|
|
801
799
|
sessionId: z
|
|
802
800
|
.string()
|
|
803
801
|
.optional()
|
|
804
802
|
.describe("Skill-run UUID for provenance stamping. Falls back to SESSION_ID env var when absent."),
|
|
805
|
-
|
|
806
|
-
.object({
|
|
807
|
-
conversationId: z.string().min(1),
|
|
808
|
-
archiveSourceFile: z.string().min(1),
|
|
809
|
-
firstMessageAt: z.string().min(1),
|
|
810
|
-
lastMessageAt: z.string().min(1),
|
|
811
|
-
participantCount: z.number().int().nonnegative(),
|
|
812
|
-
messageCount: z.number().int().nonnegative(),
|
|
813
|
-
})
|
|
814
|
-
.optional()
|
|
815
|
-
.describe("Required for archiveType='whatsapp-export'. One archive-write call writes exactly one Conversation; every row's conversationId must match this block's conversationId or the write is refused."),
|
|
816
|
-
participantNodeIds: z
|
|
817
|
-
.array(z.string().min(1))
|
|
818
|
-
.optional()
|
|
819
|
-
.describe("Required for archiveType='whatsapp-export'. Array of elementIds (:AdminUser or :Person) covering every distinct sender in `rows`. Server-side `verifyParticipants` rejects unresolved or cross-account ids before any write."),
|
|
820
|
-
archiveFilePath: z
|
|
821
|
-
.string()
|
|
822
|
-
.min(1)
|
|
823
|
-
.optional()
|
|
824
|
-
.describe("Required for archiveType='whatsapp-export' (Task 805). Operator-supplied path to the source `_chat.txt`. The server re-computes sha256 of the file bytes and asserts it matches `conversation.archiveSourceFile`. Mismatch is a hard reject before any Cypher runs — closes the silent-substitution window where an agent could pair rows[] for one file with a stale conversation block for another. Pass the same path you supplied to `whatsapp-export-parse`."),
|
|
825
|
-
}, async ({ archiveType, ownerNodeId, rows, sessionId: sessionIdOverride, conversation, participantNodeIds, archiveFilePath }) => {
|
|
803
|
+
}, async ({ archiveType, ownerNodeId, rows, sessionId: sessionIdOverride }) => {
|
|
826
804
|
try {
|
|
827
805
|
const result = await memoryArchiveWrite({
|
|
828
806
|
archiveType,
|
|
@@ -830,9 +808,6 @@ if (!readOnly) {
|
|
|
830
808
|
accountId,
|
|
831
809
|
rows: rows,
|
|
832
810
|
sessionId: resolveSessionId(sessionIdOverride),
|
|
833
|
-
conversation,
|
|
834
|
-
participantNodeIds,
|
|
835
|
-
archiveFilePath,
|
|
836
811
|
});
|
|
837
812
|
return {
|
|
838
813
|
content: [{
|
|
@@ -851,214 +826,6 @@ if (!readOnly) {
|
|
|
851
826
|
};
|
|
852
827
|
}
|
|
853
828
|
});
|
|
854
|
-
server.tool("whatsapp-export-parse", "Deterministic WhatsApp `_chat.txt` parser (Task 805). Reads the file, computes sha256 over the raw bytes, " +
|
|
855
|
-
"decodes UTF-8 (LOUD-FAIL on encoding error), and walks the line grammar — timestamp prefix, sender/body split, " +
|
|
856
|
-
"multi-line body accumulation, system-message and media-only skip patterns. Returns " +
|
|
857
|
-
"`{conversationId, archiveSourceFile, parsedLines[], counters}`. The skill consumes the result and passes the " +
|
|
858
|
-
"same `archiveSourceFile` and `archiveFilePath` to `memory-archive-write`, where the server re-computes the " +
|
|
859
|
-
"hash and asserts the parser ran on the same file. The agent never tokenises lines itself — this tool replaces " +
|
|
860
|
-
"the prose grammar in `references/export-parse.md` with deterministic code so silent line-drops cannot occur.", {
|
|
861
|
-
filePath: z
|
|
862
|
-
.string()
|
|
863
|
-
.min(1)
|
|
864
|
-
.describe("Absolute path to the `_chat.txt` file (typically dropped into chat by the operator and resolved against the attachment store)."),
|
|
865
|
-
timezone: z
|
|
866
|
-
.string()
|
|
867
|
-
.min(1)
|
|
868
|
-
.describe("IANA timezone the operator confirmed (e.g. 'Europe/London', 'America/New_York', 'UTC'). Each parsed timestamp is emitted as ISO 8601 with the offset that this zone holds for the wall-clock instant — DST is handled correctly."),
|
|
869
|
-
dateFormat: z
|
|
870
|
-
.enum(["DD/MM/YY", "MM/DD/YY", "DD/MM/YYYY", "MM/DD/YYYY"])
|
|
871
|
-
.optional()
|
|
872
|
-
.describe("Date ordering and year shape. Omit for auto-detect (Task 845): the parser probes the first matched line as DD/MM and locks that ordering if range-valid; otherwise locks MM/DD. Year shape is independent — both 2-digit (legacy) and 4-digit (modern) years are accepted within the same file. Pass an explicit value only when the operator confirms a US-locale export or when auto-detect would mis-lock on a manually concatenated multi-locale archive."),
|
|
873
|
-
}, async ({ filePath, timezone, dateFormat }) => {
|
|
874
|
-
try {
|
|
875
|
-
const result = await whatsappExportParse({
|
|
876
|
-
filePath,
|
|
877
|
-
accountId,
|
|
878
|
-
timezone,
|
|
879
|
-
dateFormat,
|
|
880
|
-
});
|
|
881
|
-
return {
|
|
882
|
-
content: [{
|
|
883
|
-
type: "text",
|
|
884
|
-
text: JSON.stringify(result),
|
|
885
|
-
}],
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
catch (err) {
|
|
889
|
-
return {
|
|
890
|
-
content: [{
|
|
891
|
-
type: "text",
|
|
892
|
-
text: `whatsapp-export-parse failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
893
|
-
}],
|
|
894
|
-
isError: true,
|
|
895
|
-
};
|
|
896
|
-
}
|
|
897
|
-
});
|
|
898
|
-
server.tool("whatsapp-export-insight-write", "Server-side gated insight-edge writer for WhatsApp imports (Task 805). Writes `:MENTIONS` edges from " +
|
|
899
|
-
"`:Message` to existing `:Person`/`:AdminUser` nodes, and `:RELATED_TO` edges between two existing distinct " +
|
|
900
|
-
"Persons. The server re-runs `memory-search` for the named entity and asserts at least one of the operator-" +
|
|
901
|
-
"supplied `candidateElementIds` matches a live result; rejects single-first-name names without a disambiguator " +
|
|
902
|
-
"flag; requires `operatorConfirmed: true` for `:RELATED_TO` writes. The agent cannot bypass these gates — they " +
|
|
903
|
-
"live in code, not in the skill markdown that prior versions of the insight pass relied on.", {
|
|
904
|
-
kind: z
|
|
905
|
-
.enum(["MENTIONS", "RELATED_TO"])
|
|
906
|
-
.describe("Edge type. MENTIONS connects a :Message to a Person/AdminUser referenced in the body. RELATED_TO connects two distinct Persons whose relationship the conversation evidences."),
|
|
907
|
-
conversationId: z
|
|
908
|
-
.string()
|
|
909
|
-
.min(1)
|
|
910
|
-
.describe("conversationId of the originating WhatsApp conversation (audit context)."),
|
|
911
|
-
messageId: z
|
|
912
|
-
.string()
|
|
913
|
-
.optional()
|
|
914
|
-
.describe("messageId of the source message — required for kind='MENTIONS', omitted for kind='RELATED_TO'."),
|
|
915
|
-
fromNodeId: z
|
|
916
|
-
.string()
|
|
917
|
-
.min(1)
|
|
918
|
-
.describe("elementId of the edge tail. For MENTIONS: the :Message. For RELATED_TO: the first :Person/:AdminUser."),
|
|
919
|
-
toNodeId: z
|
|
920
|
-
.string()
|
|
921
|
-
.min(1)
|
|
922
|
-
.describe("elementId of the edge head. For MENTIONS: the :Person/:AdminUser referenced. For RELATED_TO: the second :Person/:AdminUser."),
|
|
923
|
-
name: z
|
|
924
|
-
.string()
|
|
925
|
-
.min(1)
|
|
926
|
-
.describe("The display name as it appeared in the chat (e.g. 'Sarah', 'Sarah Chen'). Used to re-run memory-search server-side for the gate."),
|
|
927
|
-
candidateElementIds: z
|
|
928
|
-
.array(z.string().min(1))
|
|
929
|
-
.min(1)
|
|
930
|
-
.describe("Element IDs the agent's prior memory-search returned. The server re-runs the search and asserts at least one of these IDs matches a live result. If none match, the gate rejects the write (the agent's claimed evidence does not survive a fresh query)."),
|
|
931
|
-
disambiguatorOk: z
|
|
932
|
-
.boolean()
|
|
933
|
-
.optional()
|
|
934
|
-
.describe("Set to true ONLY when the chat-mention name carries an unambiguous disambiguator (full name 'Sarah Chen', explicit role context 'Sarah at Acme', email/phone). Single-first-name mentions without this flag are rejected as 'first-name-only' regardless of memory-search hit count."),
|
|
935
|
-
operatorConfirmed: z
|
|
936
|
-
.boolean()
|
|
937
|
-
.optional()
|
|
938
|
-
.describe("Set to true ONLY for RELATED_TO writes the operator has explicitly confirmed in chat. Defaults to false — every RELATED_TO without explicit confirmation is rejected to prevent inferred-relationship landfill."),
|
|
939
|
-
evidenceMessageIds: z
|
|
940
|
-
.array(z.string().min(1))
|
|
941
|
-
.optional()
|
|
942
|
-
.describe("For RELATED_TO: messageIds whose body evidenced the relationship. Stored as an edge property for forensic review."),
|
|
943
|
-
reason: z
|
|
944
|
-
.string()
|
|
945
|
-
.optional()
|
|
946
|
-
.describe("Free-text justification (one sentence) the operator can grep in audit logs. Not load-bearing for the gate; it's audit signal."),
|
|
947
|
-
sessionId: z
|
|
948
|
-
.string()
|
|
949
|
-
.optional()
|
|
950
|
-
.describe("Skill-run UUID for provenance. Falls back to SESSION_ID env var when absent."),
|
|
951
|
-
}, async (params) => {
|
|
952
|
-
try {
|
|
953
|
-
const result = await whatsappExportInsightWrite({
|
|
954
|
-
...params,
|
|
955
|
-
accountId,
|
|
956
|
-
sessionId: resolveSessionId(params.sessionId),
|
|
957
|
-
allowedScopes,
|
|
958
|
-
envAgentSlug,
|
|
959
|
-
envKeywordSubscriptions,
|
|
960
|
-
});
|
|
961
|
-
return {
|
|
962
|
-
content: [{
|
|
963
|
-
type: "text",
|
|
964
|
-
text: JSON.stringify(result),
|
|
965
|
-
}],
|
|
966
|
-
};
|
|
967
|
-
}
|
|
968
|
-
catch (err) {
|
|
969
|
-
return {
|
|
970
|
-
content: [{
|
|
971
|
-
type: "text",
|
|
972
|
-
text: `whatsapp-export-insight-write failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
973
|
-
}],
|
|
974
|
-
isError: true,
|
|
975
|
-
};
|
|
976
|
-
}
|
|
977
|
-
});
|
|
978
|
-
server.tool("whatsapp-export-preview", "Parse-only preview of a WhatsApp `_chat.txt` archive (Task 871). Returns parsed/skipped counts, " +
|
|
979
|
-
"the date range, the per-sender message histogram, the file's sha256, and total byte size — enough for the " +
|
|
980
|
-
"operator to choose a `--filter` value (`all`, `senders=<csv>`, `date-range=<isoFrom>..<isoTo>`) before invoking " +
|
|
981
|
-
"the deterministic Bash entry `whatsapp-ingest.sh`. Read-only: NO Cypher writes, NO Neo4j connection. " +
|
|
982
|
-
"Phase 1 contract — preview-then-filter-then-write. Pair with `whatsapp-ingest.sh` (Phase 1 archive-write) " +
|
|
983
|
-
"and `whatsapp-export-insight-pass` (Phase 2 enrichment) — the three tools cover the two-phase WhatsApp " +
|
|
984
|
-
"ingest pipeline.", {
|
|
985
|
-
filePath: z
|
|
986
|
-
.string()
|
|
987
|
-
.min(1)
|
|
988
|
-
.describe("Absolute path to the `_chat.txt` file (typically the operator-supplied archive path resolved against the attachment store)."),
|
|
989
|
-
timezone: z
|
|
990
|
-
.string()
|
|
991
|
-
.min(1)
|
|
992
|
-
.describe("IANA timezone the operator confirmed (e.g. 'Europe/London'). Same parameter as the parser; controls how the parsed timestamps render for the dateRange field."),
|
|
993
|
-
dateFormat: z
|
|
994
|
-
.enum(["DD/MM/YY", "MM/DD/YY", "DD/MM/YYYY", "MM/DD/YYYY"])
|
|
995
|
-
.optional()
|
|
996
|
-
.describe("Override auto-detected date ordering / year shape. Same enum as `whatsapp-export-parse`. Omit unless the operator confirms a US-locale export or a manually concatenated multi-locale archive."),
|
|
997
|
-
}, async ({ filePath, timezone, dateFormat }) => {
|
|
998
|
-
try {
|
|
999
|
-
const result = await whatsappExportPreview({
|
|
1000
|
-
filePath,
|
|
1001
|
-
accountId,
|
|
1002
|
-
timezone,
|
|
1003
|
-
dateFormat,
|
|
1004
|
-
});
|
|
1005
|
-
return {
|
|
1006
|
-
content: [{
|
|
1007
|
-
type: "text",
|
|
1008
|
-
text: JSON.stringify(result),
|
|
1009
|
-
}],
|
|
1010
|
-
};
|
|
1011
|
-
}
|
|
1012
|
-
catch (err) {
|
|
1013
|
-
return {
|
|
1014
|
-
content: [{
|
|
1015
|
-
type: "text",
|
|
1016
|
-
text: `whatsapp-export-preview failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1017
|
-
}],
|
|
1018
|
-
isError: true,
|
|
1019
|
-
};
|
|
1020
|
-
}
|
|
1021
|
-
});
|
|
1022
|
-
server.tool("whatsapp-export-insight-pass", "Phase 2 chunked-Haiku insight extraction over an already-loaded WhatsApp Conversation (Task 871). " +
|
|
1023
|
-
"Walks the Messages of `:Conversation:WhatsAppConversation {conversationId}` in chronological order, " +
|
|
1024
|
-
"chunks them at 50 messages with 5-message overlap, runs Haiku per chunk, and MERGE-keys " +
|
|
1025
|
-
"`:Observation` nodes (kind ∈ {mention, task, preference, observed-relationship}) connected " +
|
|
1026
|
-
"`:OBSERVED_IN`→Conversation. Server-side gates: confidence>=0.8 per item (lower-confidence items rejected before write). " +
|
|
1027
|
-
"Idempotent — re-running collapses identical (conversationId, sourceMessageRef, kind, contentHash) into the same row. " +
|
|
1028
|
-
"Phase 1 (`whatsapp-ingest.sh`) writes ZERO observations; this tool is the only sanctioned LLM entry for " +
|
|
1029
|
-
"WhatsApp ingest. Operator triggers consciously via the `whatsapp-import-enrich` skill — never automatic on Phase 1 completion.", {
|
|
1030
|
-
conversationId: z
|
|
1031
|
-
.string()
|
|
1032
|
-
.min(1)
|
|
1033
|
-
.describe("conversationId of the already-loaded :Conversation:WhatsAppConversation. Phase 1 must have completed (`c.lastImportedAt IS NOT NULL`)."),
|
|
1034
|
-
sessionId: z
|
|
1035
|
-
.string()
|
|
1036
|
-
.optional()
|
|
1037
|
-
.describe("Skill-run UUID for provenance. Falls back to SESSION_ID env var when absent."),
|
|
1038
|
-
}, async (params) => {
|
|
1039
|
-
try {
|
|
1040
|
-
const result = await whatsappExportInsightPass({
|
|
1041
|
-
conversationId: params.conversationId,
|
|
1042
|
-
accountId,
|
|
1043
|
-
sessionId: resolveSessionId(params.sessionId),
|
|
1044
|
-
});
|
|
1045
|
-
return {
|
|
1046
|
-
content: [{
|
|
1047
|
-
type: "text",
|
|
1048
|
-
text: JSON.stringify(result),
|
|
1049
|
-
}],
|
|
1050
|
-
};
|
|
1051
|
-
}
|
|
1052
|
-
catch (err) {
|
|
1053
|
-
return {
|
|
1054
|
-
content: [{
|
|
1055
|
-
type: "text",
|
|
1056
|
-
text: `whatsapp-export-insight-pass failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1057
|
-
}],
|
|
1058
|
-
isError: true,
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
});
|
|
1062
829
|
server.tool("memory-ingest-web", "Adapter for web-content ingestion (Task 737). Accepts a URL and its pre-fetched readable content " +
|
|
1063
830
|
"(the agent calls WebFetch first, then passes the text here), writes content to a temp file, and delegates " +
|
|
1064
831
|
"to memory-ingest-extract — caching the text under a freshly-generated attachmentId. The skill then drives " +
|
|
@@ -1587,7 +1354,7 @@ if (!readOnly) {
|
|
|
1587
1354
|
await dbSession.close();
|
|
1588
1355
|
}
|
|
1589
1356
|
});
|
|
1590
|
-
server.tool("profile-update", "Create, update, or reinforce a user preference; set top-level UserProfile fields
|
|
1357
|
+
server.tool("profile-update", "Create, update, or reinforce a user preference; set top-level UserProfile fields via profileFields; AND set Person properties on the operator's personal-profile Person via personFields. The personal-profile Person is open by default — pass any Person properties that help the agent assist this operator effectively (identity, contact, context, anything that makes future assistance more useful). The schema validator enforces rules centrally: synonyms reject (e.g. `phone` → use `telephone`), Forbidden Properties reject (e.g. `name` → use `givenName` + `familyName`), and any other key the agent judges useful is permitted. Writes route to the personal-profile Person via the OWNS edge from the AdminUser — the tool throws loudly if that edge is missing rather than silently no-oping. Supports modes: reinforce (re-observed, boost confidence), update (value changed), contradict (value contradicts prior), merge (combine overlapping preferences).", {
|
|
1591
1358
|
category: z.enum(["communication", "scheduling", "decision", "workflow", "content", "interaction"])
|
|
1592
1359
|
.describe("Preference category"),
|
|
1593
1360
|
key: z.string().describe("Preference identifier (e.g. 'response_length', 'meeting_time')"),
|
|
@@ -1600,11 +1367,8 @@ if (!readOnly) {
|
|
|
1600
1367
|
.describe("Conversation ID for evidence linking"),
|
|
1601
1368
|
profileFields: z.record(z.string(), z.unknown()).optional()
|
|
1602
1369
|
.describe("Top-level UserProfile fields to update (e.g. timezone, locale, role)"),
|
|
1603
|
-
personFields: z.
|
|
1604
|
-
|
|
1605
|
-
telephone: z.string().optional(),
|
|
1606
|
-
}).optional()
|
|
1607
|
-
.describe("Operator-identity fields written to the OWNS-bound Person (Task 886 §D). Use canonical `telephone` (NOT `phone` — that is the schema synonym, not the canonical name). Tool throws if the AdminUser-OWNS-Person edge is missing rather than silently no-op."),
|
|
1370
|
+
personFields: z.record(z.string(), z.unknown()).optional()
|
|
1371
|
+
.describe("Person properties to set on the operator's personal-profile Person — open by default; the agent decides which keys best help it serve this operator (identity, contact, context). Synonyms and Forbidden Properties are rejected by the central schema validator with descriptive errors; everything else is permitted."),
|
|
1608
1372
|
mergeSourceIds: z.array(z.string()).optional()
|
|
1609
1373
|
.describe("For mode 'merge': preferenceIds of sources to combine into this preference"),
|
|
1610
1374
|
}, async ({ category, key, value, source, mode, conversationId, profileFields, personFields, mergeSourceIds }) => {
|
|
@@ -1622,8 +1386,9 @@ if (!readOnly) {
|
|
|
1622
1386
|
mode,
|
|
1623
1387
|
conversationId,
|
|
1624
1388
|
profileFields: profileFields,
|
|
1625
|
-
personFields,
|
|
1389
|
+
personFields: personFields,
|
|
1626
1390
|
mergeSourceIds,
|
|
1391
|
+
validator,
|
|
1627
1392
|
});
|
|
1628
1393
|
return {
|
|
1629
1394
|
content: [{
|