@xopcai/xopc 0.0.155 → 0.0.157
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/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/action-boundary-settings-panel-zQ_w0sPl.js +1 -0
- package/dist/gateway/static/root/assets/{activity-store-Btmg10yU.js → activity-store-CddlQHam.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-pdlJJov8.js → agent-avatar-dicebear-DOfTopIk.js} +1 -1
- package/dist/gateway/static/root/assets/agents-RZNd9xMI.js +2 -0
- package/dist/gateway/static/root/assets/{api-GGYxPxVF.js → api-NUlcaaV9.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BU9oSmtJ.js → app-management-settings-panel-J0-z_uc1.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-B2chSkbj.js → appearance-settings-CMaQOx2C.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BOeTZgdL.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BC83GwY1.js → archive-plugin-BVwE70GV.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DWSH5325.js → attachment-load-aj5U56K9.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-Bc25f4wz.js → automation-suggestion-card-CKz8rxAb.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-wYN1N-Il.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-Kgu5yX35.js → binary-plugins-Ie6owbEw.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-B9gJmzdE.js → block-editor-BaDrd5GJ.js} +31 -31
- package/dist/gateway/static/root/assets/browser-settings-page-DD3djQtX.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-6z36IfIC.js → capability-presets-api-BjO4YD-O.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-Bqzl2UZ9.js → capability-presets-settings-panel-bwezWQpF.js} +2 -2
- package/dist/gateway/static/root/assets/{channel-recipient-api-DEkm4HRd.js → channel-recipient-api-BisDU_DH.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-Bohv9YRy.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-h3VHD5Uq.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-DPriINR1.js → connector-logo-DGjjzBIH.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-LIAkMlN-.js +2 -0
- package/dist/gateway/static/root/assets/{desktop-pet-CG91Su8E.js → desktop-pet-CoQ4Edck.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-DUzETFxq.js → desktop-pet-settings--sjUYeNX.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-XNbI2wM7.js → directory-picker-path-field-CpmfFDx3.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-BsLa5Nr8.js → dreaming-settings-D7rRROE7.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-C-5Nyrdu.js → extension-debug-page-BzqW3ssG.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BEocT43y.js → extension-page-CKDbBzVR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page--XOHrL-O.js → extension-settings-page-DjNMSdRz.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-DZrNmiR3.js → gateway-config-api-CUEAZEld.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DfBvlqb2.js → gateway-settings-h1wWBrxD.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Cc5dxiD_.js → gateway-startup-retry-CbMPgpHX.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-xfO0R5Bx.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-CVVKF2hY.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-Cdghd3f3.js → goals-config-api-C-Vq8VR9.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-W666NFIU.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-CvOdikU6.js → goals-settings-DVrTDWYS.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-CvaxjdV_.js → heartbeat-settings-Dv8qA4E7.js} +1 -1
- package/dist/gateway/static/root/assets/{index-C4HpPu1y.js → index-DHRxn7Sy.js} +61 -64
- package/dist/gateway/static/root/assets/index-gpwk8Nro.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BVt0deH6.js → keyboard-shortcuts-settings-DEKtMZbg.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-y5WmNSyZ.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-C0HGfwao.js → local-apps-page-DQT2lZk7.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-Dt0pSudQ.js → locale-store-d9Cylz62.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DMQaC4Jn.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-CjVg43Kl.js → markdown-split-Cp6NxQJr.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-D-LkrsY6.js → media-plugins-Dv1cQK2J.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-CqXpNawC.js → messages-Bwu1tG3T.js} +4 -4
- package/dist/gateway/static/root/assets/models-hub-panel-CoYDJvX_.js +2 -0
- package/dist/gateway/static/root/assets/{notes-page-BsoNcBQ3.js → notes-page-CePZ2we1.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-C9B-7EsK.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-C9OfBAT6.js → page-tabs-C1jBfKTZ.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BCrigyTS.js → preview-open-alternatives-Cl9anbg0.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DG_P8S7e.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-C1pro-bG.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-DDj6t0SQ.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-CnyZMYdJ.js → save-bar-controls-CWu_o1ta.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-Bez97_Ou.js → schedule-field-DuZbqL7X.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-DbKY5jSv.js → schema-form-Bixut-2d.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-C1aZFTTX.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CwRP1Nsl.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-4f60Dgw-.js → settings-collapsible-section-C_7lCtCp.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-CCQ7MjdZ.js → settings-form-section-D0DPTbO0.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-CQhjhb0F.js → settings-loading-skeleton-tN-9u8dj.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-C2L9g3kd.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-C7sfPFaM.js → settings-page-layout-CBUOPmx_.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DFjG5i48.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DeErzPeg.js → share-preview-page-BiSh0nLu.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-Bh2T05Hp.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-ppRtNzpM.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Dnw1xKKm.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-Dk1ZhfpM.js → system-settings-panel-h7uqbQ-n.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-Cd_gY2Cb.js → theme-store-DjYRaF0J.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-fe1xAgdw.js → typed-models-lib-BkqBD32C.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-Cbo3s1uh.js → use-channel-catalog-DiWtF12K.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-09T5O8lO.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-C4770AsA.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-D__GQy1R.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-CAIgG4im.js +1 -0
- package/dist/gateway/static/root/assets/work-page-CkZvIUpT.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-qqixrSRL.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-THxdPWzb.js +11 -0
- package/dist/gateway/static/root/connector-icons/local-files.svg +6 -0
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +63 -61
- package/dist/src/agent/embedded/xopc-auth-storage.js +1 -1
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/session-search-tool.d.ts +2 -2
- package/dist/src/agent/tools/session-search-tool.js +8 -19
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/config-surface.d.ts +0 -26
- package/dist/src/connectors/builtin-catalog.js +90 -248
- package/dist/src/connectors/composio-catalog.js +28 -1
- package/dist/src/connectors/composio-sessions.js +1 -1
- package/dist/src/connectors/composio.d.ts +1 -0
- package/dist/src/connectors/composio.js +8 -1
- package/dist/src/connectors/connector-memory-sync.d.ts +10 -0
- package/dist/src/connectors/connector-memory-sync.js +184 -38
- package/dist/src/connectors/integration-strategy.js +65 -8
- package/dist/src/connectors/memory-sync-coordinator.d.ts +28 -0
- package/dist/src/connectors/memory-sync-coordinator.js +162 -0
- package/dist/src/connectors/memory-sync-profile.d.ts +13 -0
- package/dist/src/connectors/memory-sync-profile.js +73 -0
- package/dist/src/connectors/runtime-adapter-registry.js +17 -4
- package/dist/src/connectors/runtime-status.d.ts +9 -0
- package/dist/src/connectors/runtime-status.js +68 -0
- package/dist/src/connectors/types.d.ts +2 -0
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +138 -12
- package/dist/src/gateway/hono/routes/public-gateway.js +1 -0
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +14 -0
- package/dist/src/knowledge/index.d.ts +2 -0
- package/dist/src/knowledge/index.js +3 -1
- package/dist/src/knowledge/ingestion-service.js +40 -3
- package/dist/src/knowledge/local-folder-adapter.d.ts +7 -0
- package/dist/src/knowledge/local-folder-adapter.js +86 -0
- package/dist/src/knowledge/people-graph.d.ts +28 -0
- package/dist/src/knowledge/people-graph.js +126 -0
- package/dist/src/knowledge/types.d.ts +2 -0
- package/dist/src/user-context/projection.d.ts +2 -0
- package/dist/src/user-context/projection.js +12 -2
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-NDjTqOIb.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-DHvwQknj.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-32U6mfy-.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-CTWycuu_.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-DdelF9BQ.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-CBgr61Zt.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CO3ASIfE.js +0 -2
- package/dist/gateway/static/root/assets/goal-create-dialog-BRVB5I7f.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-Drdz_llY.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-CEh2UTzg.js +0 -2
- package/dist/gateway/static/root/assets/index-DjvInkv6.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-Dcmb1Ruc.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-BWdV-HsP.js +0 -7
- package/dist/gateway/static/root/assets/models-hub-panel-Du41WFC6.js +0 -2
- package/dist/gateway/static/root/assets/notes-workbench-VeU2xG2r.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-B9QsnXWV.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BbplZbzF.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CfbuqKDd.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CSQLpHd4.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-C25HTTPK.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-BZb-E5vI.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-B1FSxWQ3.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DDg5dL3k.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-B-ocgAT-.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CtO4i9ds.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-CqtVqiYz.js +0 -1
- package/dist/gateway/static/root/assets/user-profile-fields-editor-DcnCOHwp.js +0 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-CTWZR6nV.js +0 -1
- package/dist/gateway/static/root/assets/utils-BDzZMJls.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-C9Psto-d.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-CNVeagdJ.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-DKSNc1SH.js +0 -1
- package/dist/gateway/static/root/assets/work-page-Bwbg1Ht-.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-ZKbrdYmp.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-DBHqpZ76.js +0 -11
- package/dist/gateway/static/root/connector-icons/brave-search.svg +0 -1
- package/dist/gateway/static/root/connector-icons/fetch.svg +0 -6
- package/dist/gateway/static/root/connector-icons/memory.svg +0 -5
- package/dist/gateway/static/root/connector-icons/playwright.svg +0 -9
- package/dist/gateway/static/root/connector-icons/sequential-thinking.svg +0 -8
- package/dist/gateway/static/root/connector-icons/time.svg +0 -6
|
@@ -3,17 +3,29 @@ import "../storage/sqlite/index.js";
|
|
|
3
3
|
import { ComposioSessionsAdapter } from "./composio-sessions.js";
|
|
4
4
|
import { scopeForComposioAction } from "./composio.js";
|
|
5
5
|
import { getConnectorDefinition } from "./catalog.js";
|
|
6
|
+
import { getConnectorInstance } from "./instances.js";
|
|
6
7
|
import { getWorkspacePath } from "../config/workspace-path-helpers.js";
|
|
7
8
|
import { KnowledgeIngestionService } from "../knowledge/ingestion-service.js";
|
|
8
9
|
import { ConnectedKnowledgePipeline } from "../knowledge/connected-knowledge-pipeline.js";
|
|
10
|
+
import { LocalFolderKnowledgeSourceAdapter } from "../knowledge/local-folder-adapter.js";
|
|
9
11
|
import "../knowledge/index.js";
|
|
10
12
|
import { createHash } from "node:crypto";
|
|
11
13
|
//#region src/connectors/connector-memory-sync.ts
|
|
12
|
-
const
|
|
14
|
+
const COMPOSIO_MEMORY_SOURCE_TOOLKITS = new Set([
|
|
13
15
|
"gmail",
|
|
16
|
+
"googlecalendar",
|
|
14
17
|
"googledrive",
|
|
18
|
+
"googledocs",
|
|
19
|
+
"googlesheets",
|
|
15
20
|
"notion",
|
|
16
|
-
"slack"
|
|
21
|
+
"slack",
|
|
22
|
+
"github",
|
|
23
|
+
"linear",
|
|
24
|
+
"jira",
|
|
25
|
+
"outlook",
|
|
26
|
+
"microsoft_teams",
|
|
27
|
+
"one_drive",
|
|
28
|
+
"excel"
|
|
17
29
|
]);
|
|
18
30
|
const EXTERNAL_ID_KEYS = [
|
|
19
31
|
"id",
|
|
@@ -89,9 +101,85 @@ function sanitizeSourceValue(value, depth = 0) {
|
|
|
89
101
|
if (!record) return value;
|
|
90
102
|
return Object.fromEntries(Object.entries(record).map(([key, nested]) => [key, SENSITIVE_KEY_RE.test(key) ? "[REDACTED]" : sanitizeSourceValue(nested, depth + 1)]));
|
|
91
103
|
}
|
|
104
|
+
function itemTypeFor(toolkit, actionId) {
|
|
105
|
+
if (toolkit === "gmail" || toolkit === "outlook") return "email";
|
|
106
|
+
if (toolkit === "googlecalendar" || actionId.includes("CALENDAR")) return "calendar_event";
|
|
107
|
+
if (toolkit === "slack" || toolkit === "microsoft_teams") return "conversation_message";
|
|
108
|
+
if (toolkit === "github") return "development_activity";
|
|
109
|
+
if (toolkit === "linear" || toolkit === "jira") return "work_item";
|
|
110
|
+
if ([
|
|
111
|
+
"googledrive",
|
|
112
|
+
"googledocs",
|
|
113
|
+
"googlesheets",
|
|
114
|
+
"notion",
|
|
115
|
+
"one_drive",
|
|
116
|
+
"excel"
|
|
117
|
+
].includes(toolkit)) return "document";
|
|
118
|
+
return "connector_item";
|
|
119
|
+
}
|
|
120
|
+
function boundedPersonValue(value, maxLength = 320) {
|
|
121
|
+
return typeof value === "string" ? value.trim().slice(0, maxLength) : "";
|
|
122
|
+
}
|
|
123
|
+
function personEntities(record) {
|
|
124
|
+
if (!record) return [];
|
|
125
|
+
const extractPerson = (value, role) => {
|
|
126
|
+
if (typeof value === "string") {
|
|
127
|
+
const normalized = boundedPersonValue(value);
|
|
128
|
+
if (!normalized) return [];
|
|
129
|
+
return normalized.includes("@") ? [{
|
|
130
|
+
role,
|
|
131
|
+
email: normalized
|
|
132
|
+
}] : [{
|
|
133
|
+
role,
|
|
134
|
+
name: normalized
|
|
135
|
+
}];
|
|
136
|
+
}
|
|
137
|
+
const nested = asRecord(value);
|
|
138
|
+
if (!nested) return [];
|
|
139
|
+
const name = boundedPersonValue(nested.name, 160) || boundedPersonValue(nested.displayName, 160);
|
|
140
|
+
const email = boundedPersonValue(nested.email);
|
|
141
|
+
const username = boundedPersonValue(nested.username, 160);
|
|
142
|
+
return name || email || username ? [{
|
|
143
|
+
role,
|
|
144
|
+
name: name || void 0,
|
|
145
|
+
email: email || void 0,
|
|
146
|
+
username: username || void 0
|
|
147
|
+
}] : [];
|
|
148
|
+
};
|
|
149
|
+
const entities = [
|
|
150
|
+
"email",
|
|
151
|
+
"from",
|
|
152
|
+
"sender",
|
|
153
|
+
"author",
|
|
154
|
+
"user",
|
|
155
|
+
"username",
|
|
156
|
+
"owner",
|
|
157
|
+
"assignee",
|
|
158
|
+
"attendees",
|
|
159
|
+
"participants"
|
|
160
|
+
].flatMap((key) => {
|
|
161
|
+
const value = record[key];
|
|
162
|
+
return Array.isArray(value) ? value.flatMap((item) => extractPerson(item, key)) : extractPerson(value, key);
|
|
163
|
+
});
|
|
164
|
+
const unique = /* @__PURE__ */ new Map();
|
|
165
|
+
for (const entity of entities) {
|
|
166
|
+
const key = `${entity.role}\u0000${entity.email?.toLowerCase() ?? ""}\u0000${entity.username?.toLowerCase() ?? ""}\u0000${entity.name?.toLowerCase() ?? ""}`;
|
|
167
|
+
unique.set(key, entity);
|
|
168
|
+
}
|
|
169
|
+
return [...unique.values()].slice(0, 50);
|
|
170
|
+
}
|
|
171
|
+
function peopleSignals(entities) {
|
|
172
|
+
const values = entities.flatMap((entity) => [
|
|
173
|
+
entity.email,
|
|
174
|
+
entity.name,
|
|
175
|
+
entity.username
|
|
176
|
+
]).filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean);
|
|
177
|
+
return [...new Set(values)].slice(0, 50);
|
|
178
|
+
}
|
|
92
179
|
function resultToSourceItems(input) {
|
|
93
180
|
return resultRows(input.result).slice(0, 200).map((row, index) => {
|
|
94
181
|
const record = asRecord(row);
|
|
182
|
+
const people = personEntities(record);
|
|
95
183
|
const serialized = JSON.stringify(sanitizeSourceValue(row), null, 2) ?? String(row);
|
|
96
184
|
const normalizedText = serialized.length > 8e3 ? `${serialized.slice(0, 8e3)}\n…` : serialized;
|
|
97
185
|
const contentHash = createHash("sha256").update(serialized).digest("hex");
|
|
@@ -99,7 +187,7 @@ function resultToSourceItems(input) {
|
|
|
99
187
|
return {
|
|
100
188
|
sourceInstanceId: input.sourceInstanceId,
|
|
101
189
|
externalId,
|
|
102
|
-
itemType:
|
|
190
|
+
itemType: itemTypeFor(input.toolkit, input.actionId),
|
|
103
191
|
authorRole: "third_party",
|
|
104
192
|
occurredAt: timestampField(record, OCCURRED_AT_KEYS),
|
|
105
193
|
sourceUpdatedAt: timestampField(record, UPDATED_AT_KEYS),
|
|
@@ -109,6 +197,9 @@ function resultToSourceItems(input) {
|
|
|
109
197
|
connectorId: input.connectorId,
|
|
110
198
|
connectionId: input.connectionId,
|
|
111
199
|
actionId: input.actionId,
|
|
200
|
+
toolkit: input.toolkit,
|
|
201
|
+
people: peopleSignals(people),
|
|
202
|
+
personEntities: people,
|
|
112
203
|
agentId: input.agentId,
|
|
113
204
|
workspaceId: input.workspaceId
|
|
114
205
|
},
|
|
@@ -119,11 +210,57 @@ function resultToSourceItems(input) {
|
|
|
119
210
|
};
|
|
120
211
|
});
|
|
121
212
|
}
|
|
213
|
+
var ComposioKnowledgeSourceAdapter = class {
|
|
214
|
+
kind = "composio";
|
|
215
|
+
constructor(input) {
|
|
216
|
+
this.input = input;
|
|
217
|
+
}
|
|
218
|
+
async pull(pull) {
|
|
219
|
+
const execution = await this.input.adapter.executeWithPolicy({
|
|
220
|
+
context: {
|
|
221
|
+
principalId: "local-owner",
|
|
222
|
+
toolkits: [this.input.toolkit]
|
|
223
|
+
},
|
|
224
|
+
installation: {
|
|
225
|
+
...this.input.installation,
|
|
226
|
+
maxScope: "read",
|
|
227
|
+
confirmationPolicy: "never"
|
|
228
|
+
},
|
|
229
|
+
connection: this.input.connection,
|
|
230
|
+
agentId: this.input.agentId,
|
|
231
|
+
action: {
|
|
232
|
+
connectorId: this.input.connectorId,
|
|
233
|
+
actionId: this.input.actionId,
|
|
234
|
+
toolkit: this.input.toolkit,
|
|
235
|
+
scope: "read",
|
|
236
|
+
curated: true,
|
|
237
|
+
cachedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
238
|
+
},
|
|
239
|
+
args: this.input.arguments,
|
|
240
|
+
confirmed: true
|
|
241
|
+
});
|
|
242
|
+
if (execution.decision !== "allowed") throw new Error(execution.reason);
|
|
243
|
+
return {
|
|
244
|
+
items: resultToSourceItems({
|
|
245
|
+
result: execution.result,
|
|
246
|
+
sourceInstanceId: pull.instanceId,
|
|
247
|
+
connectorId: this.input.connectorId,
|
|
248
|
+
connectionId: this.input.connection.id,
|
|
249
|
+
actionId: this.input.actionId,
|
|
250
|
+
toolkit: this.input.toolkit,
|
|
251
|
+
agentId: this.input.agentId,
|
|
252
|
+
workspaceId: this.input.workspaceId
|
|
253
|
+
}),
|
|
254
|
+
nextCursor: (/* @__PURE__ */ new Date()).toISOString(),
|
|
255
|
+
warnings: []
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
};
|
|
122
259
|
async function syncComposioResultToMemory(input) {
|
|
123
260
|
const definition = getConnectorDefinition(input.connectorId);
|
|
124
261
|
if (definition?.runtime.type !== "composio" || definition.runtime.role !== "toolkit") throw new Error("Memory sync requires a Composio toolkit connector.");
|
|
125
262
|
const toolkit = definition.runtime.toolkit;
|
|
126
|
-
if (!
|
|
263
|
+
if (!COMPOSIO_MEMORY_SOURCE_TOOLKITS.has(toolkit)) throw new Error(`Memory sync is not supported for the ${toolkit} connector.`);
|
|
127
264
|
const risk = scopeForComposioAction(input.actionId);
|
|
128
265
|
if (risk.toolkit !== toolkit || risk.scope !== "read" || !risk.curated) throw new Error("Memory sync only accepts a verified read action for the selected connector.");
|
|
129
266
|
const connectorId = definition.id;
|
|
@@ -136,46 +273,25 @@ async function syncComposioResultToMemory(input) {
|
|
|
136
273
|
}).filter((connection) => connection.status === "active");
|
|
137
274
|
const connection = input.connectionId ? activeConnections.find((candidate) => candidate.id === input.connectionId) : activeConnections.find((candidate) => candidate.isDefault) ?? activeConnections[0];
|
|
138
275
|
if (!connection) throw new Error("No active connector account is available for memory sync.");
|
|
139
|
-
const
|
|
140
|
-
context: {
|
|
141
|
-
principalId: "local-owner",
|
|
142
|
-
toolkits: [toolkit]
|
|
143
|
-
},
|
|
144
|
-
installation: {
|
|
145
|
-
...installation,
|
|
146
|
-
maxScope: "read",
|
|
147
|
-
confirmationPolicy: "never"
|
|
148
|
-
},
|
|
149
|
-
connection,
|
|
150
|
-
agentId: input.agentId,
|
|
151
|
-
action: {
|
|
152
|
-
connectorId,
|
|
153
|
-
actionId: input.actionId,
|
|
154
|
-
toolkit,
|
|
155
|
-
scope: "read",
|
|
156
|
-
curated: true,
|
|
157
|
-
cachedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
158
|
-
},
|
|
159
|
-
args: input.arguments ?? {},
|
|
160
|
-
confirmed: true
|
|
161
|
-
});
|
|
162
|
-
if (execution.decision !== "allowed") throw new Error(execution.reason);
|
|
276
|
+
const adapter = input.adapter ?? new ComposioSessionsAdapter();
|
|
163
277
|
const workspaceId = getWorkspacePath(input.config);
|
|
164
278
|
const sourceInstanceId = `composio:${connectorId}:${connection.id}`;
|
|
165
|
-
const
|
|
166
|
-
result: execution.result,
|
|
167
|
-
sourceInstanceId,
|
|
279
|
+
const sourceAdapter = new ComposioKnowledgeSourceAdapter({
|
|
168
280
|
connectorId,
|
|
169
|
-
|
|
281
|
+
connection,
|
|
170
282
|
actionId: input.actionId,
|
|
283
|
+
arguments: input.arguments ?? {},
|
|
171
284
|
agentId: input.agentId,
|
|
172
|
-
|
|
285
|
+
toolkit,
|
|
286
|
+
workspaceId,
|
|
287
|
+
installation,
|
|
288
|
+
adapter
|
|
173
289
|
});
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
cursorAfter: (/* @__PURE__ */ new Date()).toISOString()
|
|
290
|
+
const syncRun = await new KnowledgeIngestionService(new Map([[sourceAdapter.kind, sourceAdapter]])).sync({
|
|
291
|
+
adapterKind: sourceAdapter.kind,
|
|
292
|
+
instanceId: sourceInstanceId
|
|
178
293
|
});
|
|
294
|
+
if (syncRun.status === "failed" || syncRun.status === "cancelled") throw new Error(syncRun.error ?? `Connector memory sync ${syncRun.status}.`);
|
|
179
295
|
const pipeline = new ConnectedKnowledgePipeline({
|
|
180
296
|
agentId: input.agentId,
|
|
181
297
|
workspaceId
|
|
@@ -193,5 +309,35 @@ async function syncComposioResultToMemory(input) {
|
|
|
193
309
|
actionId: input.actionId
|
|
194
310
|
};
|
|
195
311
|
}
|
|
312
|
+
async function syncLocalFolderToMemory(input) {
|
|
313
|
+
const definition = getConnectorDefinition(input.connectorId);
|
|
314
|
+
if (definition?.runtime.type !== "memorySource" || definition.runtime.sourceKind !== "local-folder") throw new Error("Local folder sync requires a local-folder memory source connector.");
|
|
315
|
+
const instance = getConnectorInstance(input.config, definition.id);
|
|
316
|
+
if (!instance?.enabled) throw new Error("Local folder connector is not installed and enabled.");
|
|
317
|
+
const rootPath = typeof instance.config?.rootPath === "string" ? instance.config.rootPath.trim() : "";
|
|
318
|
+
if (!rootPath) throw new Error("Local folder connector requires a rootPath.");
|
|
319
|
+
const sourceInstanceId = `local-folder:${definition.id}`;
|
|
320
|
+
const adapter = new LocalFolderKnowledgeSourceAdapter(rootPath);
|
|
321
|
+
const syncRun = await new KnowledgeIngestionService(new Map([[adapter.kind, adapter]])).sync({
|
|
322
|
+
adapterKind: adapter.kind,
|
|
323
|
+
instanceId: sourceInstanceId
|
|
324
|
+
});
|
|
325
|
+
if (syncRun.status === "failed" || syncRun.status === "cancelled") throw new Error(syncRun.error ?? `Local folder sync ${syncRun.status}.`);
|
|
326
|
+
const pipeline = new ConnectedKnowledgePipeline({
|
|
327
|
+
agentId: input.agentId,
|
|
328
|
+
workspaceId: getWorkspacePath(input.config)
|
|
329
|
+
});
|
|
330
|
+
const recordIds = [];
|
|
331
|
+
for (let batch = 0; batch < 10; batch += 1) {
|
|
332
|
+
const synthesis = await pipeline.processPending(sourceInstanceId);
|
|
333
|
+
recordIds.push(...synthesis.recordIds);
|
|
334
|
+
if (synthesis.claimed === 0) break;
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
connectorId: definition.id,
|
|
338
|
+
sourceInstanceId,
|
|
339
|
+
recordIds
|
|
340
|
+
};
|
|
341
|
+
}
|
|
196
342
|
//#endregion
|
|
197
|
-
export { syncComposioResultToMemory };
|
|
343
|
+
export { COMPOSIO_MEMORY_SOURCE_TOOLKITS, syncComposioResultToMemory, syncLocalFolderToMemory };
|
|
@@ -1,13 +1,70 @@
|
|
|
1
1
|
//#region src/connectors/integration-strategy.ts
|
|
2
|
-
const COMPOSIO_STRATEGY_OVERRIDES = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
const COMPOSIO_STRATEGY_OVERRIDES = {
|
|
3
|
+
gmail: {
|
|
4
|
+
lane: "composio",
|
|
5
|
+
workload: "core",
|
|
6
|
+
preferred: true
|
|
7
|
+
},
|
|
8
|
+
googlecalendar: {
|
|
9
|
+
lane: "composio",
|
|
10
|
+
workload: "core",
|
|
11
|
+
preferred: true
|
|
12
|
+
},
|
|
13
|
+
googledrive: {
|
|
14
|
+
lane: "composio",
|
|
15
|
+
workload: "core",
|
|
16
|
+
preferred: true
|
|
17
|
+
},
|
|
18
|
+
notion: {
|
|
19
|
+
lane: "composio",
|
|
20
|
+
workload: "core",
|
|
21
|
+
preferred: true
|
|
22
|
+
},
|
|
23
|
+
slack: {
|
|
24
|
+
lane: "composio",
|
|
25
|
+
workload: "core",
|
|
26
|
+
preferred: true
|
|
27
|
+
},
|
|
28
|
+
github: {
|
|
29
|
+
lane: "composio",
|
|
30
|
+
workload: "core",
|
|
31
|
+
preferred: true
|
|
32
|
+
},
|
|
33
|
+
linear: {
|
|
34
|
+
lane: "composio",
|
|
35
|
+
workload: "core",
|
|
36
|
+
preferred: true
|
|
37
|
+
},
|
|
38
|
+
jira: {
|
|
39
|
+
lane: "composio",
|
|
40
|
+
workload: "core",
|
|
41
|
+
preferred: true
|
|
42
|
+
},
|
|
43
|
+
outlook: {
|
|
44
|
+
lane: "composio",
|
|
45
|
+
workload: "core",
|
|
46
|
+
preferred: true
|
|
47
|
+
},
|
|
48
|
+
microsoft_teams: {
|
|
49
|
+
lane: "composio",
|
|
50
|
+
workload: "core",
|
|
51
|
+
preferred: true
|
|
52
|
+
},
|
|
53
|
+
one_drive: {
|
|
54
|
+
lane: "composio",
|
|
55
|
+
workload: "core",
|
|
56
|
+
preferred: true
|
|
57
|
+
},
|
|
58
|
+
telegram: {
|
|
59
|
+
lane: "native",
|
|
60
|
+
workload: "core",
|
|
61
|
+
preferred: false,
|
|
62
|
+
alternative: {
|
|
63
|
+
kind: "channel",
|
|
64
|
+
id: "telegram"
|
|
65
|
+
}
|
|
9
66
|
}
|
|
10
|
-
}
|
|
67
|
+
};
|
|
11
68
|
function composioIntegrationStrategy(toolkit) {
|
|
12
69
|
return COMPOSIO_STRATEGY_OVERRIDES[toolkit.trim().toLowerCase()] ?? {
|
|
13
70
|
lane: "composio",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
import { syncComposioResultToMemory, syncLocalFolderToMemory } from './connector-memory-sync.js';
|
|
3
|
+
export type ConnectorMemorySyncCoordinator = {
|
|
4
|
+
runNow(options?: {
|
|
5
|
+
toolkit?: string;
|
|
6
|
+
force?: boolean;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
stop(): void;
|
|
9
|
+
};
|
|
10
|
+
export declare function syncDueMemorySources(options: {
|
|
11
|
+
config: Config;
|
|
12
|
+
agentId: string;
|
|
13
|
+
nowMs?: number;
|
|
14
|
+
toolkit?: string;
|
|
15
|
+
force?: boolean;
|
|
16
|
+
syncLocalSource?: typeof syncLocalFolderToMemory;
|
|
17
|
+
syncComposioSource?: typeof syncComposioResultToMemory;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
eligible: number;
|
|
20
|
+
synced: number;
|
|
21
|
+
failed: number;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function startConnectorMemorySyncCoordinator(options: {
|
|
24
|
+
getConfig: () => Config;
|
|
25
|
+
resolveAgentId: () => string;
|
|
26
|
+
intervalMs?: number;
|
|
27
|
+
initialDelayMs?: number;
|
|
28
|
+
}): ConnectorMemorySyncCoordinator;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { listKnowledgeSyncRuns } from "../storage/sqlite/knowledge-repository.js";
|
|
4
|
+
import { listConnectorConnections } from "../storage/sqlite/connector-repository.js";
|
|
5
|
+
import "../storage/sqlite/index.js";
|
|
6
|
+
import { getConnectorDefinition } from "./catalog.js";
|
|
7
|
+
import { listConnectorInstances } from "./instances.js";
|
|
8
|
+
import { syncComposioResultToMemory, syncLocalFolderToMemory } from "./connector-memory-sync.js";
|
|
9
|
+
import { getComposioMemorySyncProfile } from "./memory-sync-profile.js";
|
|
10
|
+
//#region src/connectors/memory-sync-coordinator.ts
|
|
11
|
+
init_logger();
|
|
12
|
+
const log = createLogger("ConnectorMemorySync");
|
|
13
|
+
const DEFAULT_SYNC_INTERVAL_MINUTES = 15;
|
|
14
|
+
async function syncDueMemorySources(options) {
|
|
15
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
16
|
+
const syncLocalSource = options.syncLocalSource ?? syncLocalFolderToMemory;
|
|
17
|
+
const syncComposioSource = options.syncComposioSource ?? syncComposioResultToMemory;
|
|
18
|
+
let eligible = 0;
|
|
19
|
+
let synced = 0;
|
|
20
|
+
let failed = 0;
|
|
21
|
+
for (const instance of listConnectorInstances(options.config)) {
|
|
22
|
+
if (!instance.enabled) continue;
|
|
23
|
+
const definition = getConnectorDefinition(instance.connectorId);
|
|
24
|
+
if (definition?.runtime.type === "memorySource" && definition.runtime.sourceKind === "local-folder") {
|
|
25
|
+
if (options.toolkit || instance.config?.autoSync === false) continue;
|
|
26
|
+
eligible += 1;
|
|
27
|
+
const configuredMinutes = Number(instance.config?.syncIntervalMinutes ?? DEFAULT_SYNC_INTERVAL_MINUTES);
|
|
28
|
+
const intervalMinutes = Number.isFinite(configuredMinutes) ? Math.max(5, Math.min(configuredMinutes, 1440)) : DEFAULT_SYNC_INTERVAL_MINUTES;
|
|
29
|
+
const sourceInstanceId = `local-folder:${definition.id}`;
|
|
30
|
+
const latestRun = listKnowledgeSyncRuns({
|
|
31
|
+
sourceInstanceId,
|
|
32
|
+
limit: 1
|
|
33
|
+
})[0];
|
|
34
|
+
if (!options.force && latestRun && nowMs - Date.parse(latestRun.startedAt) < intervalMinutes * 6e4) continue;
|
|
35
|
+
try {
|
|
36
|
+
await syncLocalSource({
|
|
37
|
+
config: options.config,
|
|
38
|
+
connectorId: definition.id,
|
|
39
|
+
agentId: options.agentId
|
|
40
|
+
});
|
|
41
|
+
synced += 1;
|
|
42
|
+
} catch (err) {
|
|
43
|
+
failed += 1;
|
|
44
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
45
|
+
log.warn({
|
|
46
|
+
err,
|
|
47
|
+
connectorId: definition.id,
|
|
48
|
+
sourceInstanceId
|
|
49
|
+
}, `Automatic connector memory sync failed: ${errorMessage}`);
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (definition?.runtime.type !== "composio" || definition.runtime.role !== "toolkit") continue;
|
|
54
|
+
if (options.toolkit && definition.runtime.toolkit !== options.toolkit) continue;
|
|
55
|
+
const profile = getComposioMemorySyncProfile(options.config, definition.id);
|
|
56
|
+
if (!profile?.enabled || options.force && options.toolkit && !profile.triggerSync) continue;
|
|
57
|
+
eligible += 1;
|
|
58
|
+
const activeConnections = listConnectorConnections({ connectorId: definition.id }).filter((candidate) => candidate.status === "active");
|
|
59
|
+
const connection = profile.connectionId ? activeConnections.find((candidate) => candidate.id === profile.connectionId) : activeConnections.find((candidate) => candidate.isDefault) ?? activeConnections[0];
|
|
60
|
+
if (!connection) continue;
|
|
61
|
+
const sourceInstanceId = `composio:${definition.id}:${connection.id}`;
|
|
62
|
+
const latestRun = listKnowledgeSyncRuns({
|
|
63
|
+
sourceInstanceId,
|
|
64
|
+
limit: 1
|
|
65
|
+
})[0];
|
|
66
|
+
if (!options.force && latestRun && nowMs - Date.parse(latestRun.startedAt) < profile.intervalMinutes * 6e4) continue;
|
|
67
|
+
try {
|
|
68
|
+
await syncComposioSource({
|
|
69
|
+
config: options.config,
|
|
70
|
+
connectorId: definition.id,
|
|
71
|
+
actionId: profile.actionId,
|
|
72
|
+
arguments: profile.arguments,
|
|
73
|
+
agentId: profile.agentId,
|
|
74
|
+
connectionId: connection.id
|
|
75
|
+
});
|
|
76
|
+
synced += 1;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
failed += 1;
|
|
79
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
80
|
+
log.warn({
|
|
81
|
+
err,
|
|
82
|
+
connectorId: definition.id,
|
|
83
|
+
sourceInstanceId
|
|
84
|
+
}, `Automatic Composio memory sync failed: ${errorMessage}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
eligible,
|
|
89
|
+
synced,
|
|
90
|
+
failed
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function startConnectorMemorySyncCoordinator(options) {
|
|
94
|
+
const intervalMs = Math.max(1e4, Math.min(options.intervalMs ?? 6e4, 30 * 6e4));
|
|
95
|
+
let timer = null;
|
|
96
|
+
let running = false;
|
|
97
|
+
let stopped = false;
|
|
98
|
+
let pendingAll = false;
|
|
99
|
+
let pendingForce = false;
|
|
100
|
+
const pendingToolkits = /* @__PURE__ */ new Set();
|
|
101
|
+
async function runNow(runOptions) {
|
|
102
|
+
if (stopped) return;
|
|
103
|
+
if (running) {
|
|
104
|
+
if (runOptions?.toolkit) pendingToolkits.add(runOptions.toolkit);
|
|
105
|
+
else pendingAll = true;
|
|
106
|
+
pendingForce ||= runOptions?.force === true;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
running = true;
|
|
110
|
+
try {
|
|
111
|
+
const result = await syncDueMemorySources({
|
|
112
|
+
config: options.getConfig(),
|
|
113
|
+
agentId: options.resolveAgentId(),
|
|
114
|
+
toolkit: runOptions?.toolkit,
|
|
115
|
+
force: runOptions?.force
|
|
116
|
+
});
|
|
117
|
+
if (result.synced > 0 || result.failed > 0) log.info(result, "Automatic connector memory sync cycle completed");
|
|
118
|
+
} catch (err) {
|
|
119
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
120
|
+
log.warn({ err }, `Automatic connector memory sync cycle failed: ${errorMessage}`);
|
|
121
|
+
} finally {
|
|
122
|
+
running = false;
|
|
123
|
+
if (!stopped && (pendingAll || pendingToolkits.size > 0)) {
|
|
124
|
+
const runAll = pendingAll;
|
|
125
|
+
const force = pendingForce;
|
|
126
|
+
const toolkits = [...pendingToolkits];
|
|
127
|
+
pendingAll = false;
|
|
128
|
+
pendingForce = false;
|
|
129
|
+
pendingToolkits.clear();
|
|
130
|
+
queueMicrotask(() => {
|
|
131
|
+
if (runAll) runNow({ force });
|
|
132
|
+
else toolkits.reduce(async (previous, toolkit) => {
|
|
133
|
+
await previous;
|
|
134
|
+
await runNow({
|
|
135
|
+
toolkit,
|
|
136
|
+
force
|
|
137
|
+
});
|
|
138
|
+
}, Promise.resolve());
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
timer = setTimeout(() => {
|
|
144
|
+
runNow();
|
|
145
|
+
timer = setInterval(() => void runNow(), intervalMs);
|
|
146
|
+
timer.unref?.();
|
|
147
|
+
}, Math.max(0, options.initialDelayMs ?? 1e4));
|
|
148
|
+
timer.unref?.();
|
|
149
|
+
return {
|
|
150
|
+
runNow,
|
|
151
|
+
stop() {
|
|
152
|
+
stopped = true;
|
|
153
|
+
if (timer) {
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
clearInterval(timer);
|
|
156
|
+
timer = null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//#endregion
|
|
162
|
+
export { startConnectorMemorySyncCoordinator, syncDueMemorySources };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
export type ComposioMemorySyncProfile = {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
actionId: string;
|
|
5
|
+
arguments: Record<string, unknown>;
|
|
6
|
+
agentId: string;
|
|
7
|
+
connectionId?: string;
|
|
8
|
+
intervalMinutes: number;
|
|
9
|
+
triggerSync: boolean;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function getComposioMemorySyncProfile(config: Config, connectorId: string): ComposioMemorySyncProfile | undefined;
|
|
13
|
+
export declare function updateComposioMemorySyncProfile(config: Config, connectorId: string, input: Omit<ComposioMemorySyncProfile, 'updatedAt'>): ComposioMemorySyncProfile;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { scopeForComposioAction } from "./composio.js";
|
|
2
|
+
import { getConnectorDefinition } from "./catalog.js";
|
|
3
|
+
import { COMPOSIO_MEMORY_SOURCE_TOOLKITS } from "./connector-memory-sync.js";
|
|
4
|
+
//#region src/connectors/memory-sync-profile.ts
|
|
5
|
+
const SENSITIVE_ARGUMENT_KEY = /(?:api[-_]?key|authorization|cookie|password|secret|token)/i;
|
|
6
|
+
function asRecord(value) {
|
|
7
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
8
|
+
}
|
|
9
|
+
function assertNoPersistedSecrets(value, depth = 0) {
|
|
10
|
+
if (depth > 12) throw new Error("Memory sync arguments are nested too deeply.");
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
for (const item of value) assertNoPersistedSecrets(item, depth + 1);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const record = asRecord(value);
|
|
16
|
+
if (!record) return;
|
|
17
|
+
for (const [key, nested] of Object.entries(record)) {
|
|
18
|
+
if (SENSITIVE_ARGUMENT_KEY.test(key)) throw new Error(`Memory sync arguments cannot persist sensitive field "${key}".`);
|
|
19
|
+
assertNoPersistedSecrets(nested, depth + 1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function markerFor(config, connectorId) {
|
|
23
|
+
return asRecord(config.connectors?.instances?.[connectorId]?.xopcConnector);
|
|
24
|
+
}
|
|
25
|
+
function getComposioMemorySyncProfile(config, connectorId) {
|
|
26
|
+
const raw = asRecord(asRecord(markerFor(config, connectorId)?.config)?.memorySync);
|
|
27
|
+
if (!raw) return void 0;
|
|
28
|
+
const actionId = typeof raw.actionId === "string" ? raw.actionId.trim() : "";
|
|
29
|
+
const agentId = typeof raw.agentId === "string" ? raw.agentId.trim() : "";
|
|
30
|
+
if (!actionId || !agentId) return void 0;
|
|
31
|
+
const interval = Number(raw.intervalMinutes);
|
|
32
|
+
return {
|
|
33
|
+
enabled: raw.enabled === true,
|
|
34
|
+
actionId,
|
|
35
|
+
arguments: asRecord(raw.arguments) ?? {},
|
|
36
|
+
agentId,
|
|
37
|
+
connectionId: typeof raw.connectionId === "string" && raw.connectionId.trim() ? raw.connectionId.trim() : void 0,
|
|
38
|
+
intervalMinutes: Number.isFinite(interval) ? Math.max(5, Math.min(interval, 1440)) : 15,
|
|
39
|
+
triggerSync: raw.triggerSync !== false,
|
|
40
|
+
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : (/* @__PURE__ */ new Date(0)).toISOString()
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function updateComposioMemorySyncProfile(config, connectorId, input) {
|
|
44
|
+
const definition = getConnectorDefinition(connectorId);
|
|
45
|
+
if (definition?.runtime.type !== "composio" || definition.runtime.role !== "toolkit") throw new Error("Memory sync profiles require an installed Composio toolkit connector.");
|
|
46
|
+
const toolkit = definition.runtime.toolkit;
|
|
47
|
+
if (!COMPOSIO_MEMORY_SOURCE_TOOLKITS.has(toolkit)) throw new Error(`Memory sync is not supported for the ${toolkit} connector.`);
|
|
48
|
+
const marker = markerFor(config, connectorId);
|
|
49
|
+
if (!marker || marker.managed !== true || marker.enabled === false) throw new Error(`Connector is not installed and enabled: ${connectorId}`);
|
|
50
|
+
const actionId = input.actionId.trim();
|
|
51
|
+
const agentId = input.agentId.trim();
|
|
52
|
+
const risk = scopeForComposioAction(actionId);
|
|
53
|
+
if (!actionId || risk.toolkit !== toolkit || risk.scope !== "read" || !risk.curated) throw new Error("Memory sync profiles require a curated read-only action from the same toolkit.");
|
|
54
|
+
if (!agentId) throw new Error("Memory sync profile requires an agentId.");
|
|
55
|
+
assertNoPersistedSecrets(input.arguments);
|
|
56
|
+
const profile = {
|
|
57
|
+
enabled: input.enabled,
|
|
58
|
+
actionId,
|
|
59
|
+
arguments: structuredClone(input.arguments),
|
|
60
|
+
agentId,
|
|
61
|
+
connectionId: input.connectionId?.trim() || void 0,
|
|
62
|
+
intervalMinutes: Math.max(5, Math.min(Number(input.intervalMinutes) || 15, 1440)),
|
|
63
|
+
triggerSync: input.triggerSync,
|
|
64
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
65
|
+
};
|
|
66
|
+
marker.config = {
|
|
67
|
+
...asRecord(marker.config) ?? {},
|
|
68
|
+
memorySync: profile
|
|
69
|
+
};
|
|
70
|
+
return profile;
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { getComposioMemorySyncProfile, updateComposioMemorySyncProfile };
|
|
@@ -18,7 +18,7 @@ function installedInstance(config, instanceId, connectorId) {
|
|
|
18
18
|
if (!instance) throw new Error(`Connector "${connectorId}" was installed but could not be resolved.`);
|
|
19
19
|
return instance;
|
|
20
20
|
}
|
|
21
|
-
function installRecord(config, definition, extra = {}) {
|
|
21
|
+
function installRecord(config, definition, extra = {}, markerExtra = {}) {
|
|
22
22
|
const instanceId = definition.id;
|
|
23
23
|
config.connectors = config.connectors ?? {};
|
|
24
24
|
config.connectors.instances = {
|
|
@@ -31,7 +31,8 @@ function installRecord(config, definition, extra = {}) {
|
|
|
31
31
|
enabled: true,
|
|
32
32
|
displayName: definition.displayName,
|
|
33
33
|
source: definition.source,
|
|
34
|
-
artifactSha256: definition.provenance?.sha256
|
|
34
|
+
artifactSha256: definition.provenance?.sha256,
|
|
35
|
+
...markerExtra
|
|
35
36
|
},
|
|
36
37
|
runtime: definition.runtime,
|
|
37
38
|
...extra
|
|
@@ -136,11 +137,23 @@ for (const type of [
|
|
|
136
137
|
"memorySource"
|
|
137
138
|
]) registerConnectorRuntimeAdapter({
|
|
138
139
|
type,
|
|
139
|
-
async install({ config, definition }) {
|
|
140
|
-
return installRecord(config, definition);
|
|
140
|
+
async install({ config, definition, input }) {
|
|
141
|
+
return installRecord(config, definition, {}, { config: input.config ?? {} });
|
|
141
142
|
},
|
|
142
143
|
uninstall({ config, instance }) {
|
|
143
144
|
uninstallRecord(config, instance.instanceId);
|
|
145
|
+
},
|
|
146
|
+
update({ config, definition, input, instanceId }) {
|
|
147
|
+
const record = config.connectors?.instances?.[instanceId];
|
|
148
|
+
const marker = record?.xopcConnector;
|
|
149
|
+
if (!marker || typeof marker !== "object" || Array.isArray(marker)) throw new Error(`Connector instance not found: ${instanceId}`);
|
|
150
|
+
const markerRecord = marker;
|
|
151
|
+
if (markerRecord.managed !== true) throw new Error(`Connector instance not found: ${instanceId}`);
|
|
152
|
+
record.xopcConnector = {
|
|
153
|
+
...markerRecord,
|
|
154
|
+
config: input.config ?? {}
|
|
155
|
+
};
|
|
156
|
+
return installedInstance(config, instanceId, definition.id);
|
|
144
157
|
}
|
|
145
158
|
});
|
|
146
159
|
function getConnectorRuntimeAdapter(type) {
|