studiograph 1.2.0-beta.7 → 1.2.0-beta.9
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/agent/orchestrator.d.ts +1 -0
- package/dist/agent/orchestrator.js +3 -1
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/skills/bundled/enrich-entities.md +124 -0
- package/dist/agent/skills/bundled/gather-context.md +46 -0
- package/dist/agent/skills/sync-setup.md +17 -1
- package/dist/agent/tools/sync-tools.d.ts +9 -1
- package/dist/agent/tools/sync-tools.js +257 -1
- package/dist/agent/tools/sync-tools.js.map +1 -1
- package/dist/cli/commands/start.js +3 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/core/graph.d.ts +2 -0
- package/dist/core/graph.js +4 -4
- package/dist/core/graph.js.map +1 -1
- package/package.json +1 -1
- package/dist/core/migration-runner.d.ts +0 -42
- package/dist/core/migration-runner.js +0 -232
- package/dist/core/migration-runner.js.map +0 -1
- package/dist/core/migration-types.d.ts +0 -101
- package/dist/core/migration-types.js +0 -21
- package/dist/core/migration-types.js.map +0 -1
- package/dist/core/migrations/20260219-formalize-memory-location.d.ts +0 -2
- package/dist/core/migrations/20260219-formalize-memory-location.js +0 -35
- package/dist/core/migrations/20260219-formalize-memory-location.js.map +0 -1
- package/dist/core/migrations/20260220-add-workspace-metadata.d.ts +0 -12
- package/dist/core/migrations/20260220-add-workspace-metadata.js +0 -65
- package/dist/core/migrations/20260220-add-workspace-metadata.js.map +0 -1
- package/dist/core/migrations/20260220-add-workspace-readme.d.ts +0 -11
- package/dist/core/migrations/20260220-add-workspace-readme.js +0 -82
- package/dist/core/migrations/20260220-add-workspace-readme.js.map +0 -1
- package/dist/core/migrations/20260220-migrate-yaml-to-json.d.ts +0 -9
- package/dist/core/migrations/20260220-migrate-yaml-to-json.js +0 -64
- package/dist/core/migrations/20260220-migrate-yaml-to-json.js.map +0 -1
- package/dist/core/migrations/index.d.ts +0 -11
- package/dist/core/migrations/index.js +0 -23
- package/dist/core/migrations/index.js.map +0 -1
|
@@ -31,6 +31,7 @@ export class AgentOrchestrator {
|
|
|
31
31
|
gitUser;
|
|
32
32
|
skillsDirs;
|
|
33
33
|
toolsDirs;
|
|
34
|
+
registryRef = { registry: null };
|
|
34
35
|
constructor(config) {
|
|
35
36
|
this.workspacePath = config.workspacePath;
|
|
36
37
|
this.config = config.workspaceConfig;
|
|
@@ -68,7 +69,7 @@ export class AgentOrchestrator {
|
|
|
68
69
|
// Build tools first so we can auto-generate the tool reference for the prompt
|
|
69
70
|
const tools = [
|
|
70
71
|
...createGraphTools(this.workspaceManager, this.gitUser, this.workspacePath),
|
|
71
|
-
...createSyncTools(this.workspacePath, this.config),
|
|
72
|
+
...createSyncTools(this.workspacePath, this.config, this.registryRef),
|
|
72
73
|
...createOpsTools(this.workspacePath, this.config),
|
|
73
74
|
...createFsTools(),
|
|
74
75
|
createLoadSkillTool(skillIndex),
|
|
@@ -101,6 +102,7 @@ export class AgentOrchestrator {
|
|
|
101
102
|
if (connectorTools.length > 0) {
|
|
102
103
|
const registry = buildConnectorRegistry(connectorTools);
|
|
103
104
|
extra.push(...createConnectorTools(registry));
|
|
105
|
+
this.registryRef.registry = registry;
|
|
104
106
|
}
|
|
105
107
|
if (extra.length > 0) {
|
|
106
108
|
const existing = agent.state.tools;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/agent/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAe,MAAM,IAAI,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/agent/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAe,MAAM,IAAI,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAwB,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAqBhF,MAAM,OAAO,iBAAiB;IACpB,aAAa,CAAS;IACtB,gBAAgB,CAAmB;IACnC,KAAK,CAAQ;IACb,MAAM,CAAkB;IACxB,OAAO,CAAU;IACjB,UAAU,CAAW;IACrB,SAAS,CAAW;IACpB,WAAW,GAAyB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAE/D,YAAY,MAAmB;QAC7B,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;QACrC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAE9B,gEAAgE;QAChE,2EAA2E;QAC3E,MAAM,aAAa,GAAQ,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;QACrE,MAAM,YAAY,GAAS,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QACpE,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;QAC9E,MAAM,iBAAiB,GAAI,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAC7E,MAAM,gBAAgB,GAAK,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAErD,IAAI,CAAC,UAAU,GAAG,CAAC,aAAa,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC;QACtG,IAAI,CAAC,SAAS,GAAI,CAAC,YAAY,EAAG,iBAAiB,EAAG,GAAG,CAAC,MAAM,CAAC,SAAS,IAAK,EAAE,CAAC,CAAC,CAAC;QAEpF,+BAA+B;QAC/B,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAgB,EAAE,CAAC;QACrE,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,CAC1C,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,OAAO,EACZ,gBAAgB,CACjB,CAAC;QAEF,+DAA+D;QAC/D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED;;;OAGG;IACK,WAAW;QACjB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,UAAU,CAAC,cAAc,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,WAAW,CAAC;QACxF,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,4BAA4B,CAAC;QAC5F,MAAM,MAAM,GAAG,sBAAsB,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;QAEhH,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAe,EAAE,OAAc,CAAC,CAAC;QAExD,oEAAoE;QACpE,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEnD,8EAA8E;QAC9E,MAAM,KAAK,GAAU;YACnB,GAAG,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;YAC5E,GAAG,eAAe,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC;YACrE,GAAG,cAAc,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC;YAClD,GAAG,aAAa,EAAE;YAClB,mBAAmB,CAAC,UAAU,CAAC;SAChC,CAAC;QAEF,0FAA0F;QAC1F,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAE/D,kCAAkC;QAClC,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,MAAM,sBAAsB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEhG,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;QACrD,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtB,KAAK,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;QACpC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEtB,qDAAqD;QACrD,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAEjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;OAKG;IACK,oBAAoB,CAAC,KAAY;QACvC,MAAM,OAAO,GAAG,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACnF,OAAO,CAAC,GAAG,CAAC;YACV,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;YACxC,gBAAgB,CAAC,UAAU,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC;SAC5D,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC;YAC/B,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC;gBACxD,KAAK,CAAC,IAAI,CAAC,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC9C,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACvC,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;gBACnC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;YACb,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAC,UAAmD,EAAE,KAAY;QACzF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;QAC3D,IAAI,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC;YAC/B,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC;YACnC,CAAC,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAElC,0EAA0E;QAC1E,MAAM,UAAU,GAA0B;YACxC,mBAAmB,EAAE,EAAE;YACvB,2BAA2B,EAAE,EAAE;YAC/B,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,EAAE;YACnB,qBAAqB,EAAE,EAAE;YACzB,YAAY,EAAE,EAAE;YAChB,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,CAAC,WAAW,EAAE,UAAU,CAAC,YAAY,CAAC;gBAAE,SAAS;YACtD,MAAM,IAAI,GAAW,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAClC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,UAAU,CAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBACzE,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;gBAAE,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBACjE,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;gBAAE,UAAU,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBACvE,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;gBAAE,UAAU,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBAC7E,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;gBAAE,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBAC5F,IAAI,IAAI,KAAK,YAAY;gBAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBACxD,IAAI,CAAC,eAAe,EAAC,YAAY,EAAC,eAAe,EAAC,eAAe,EAAC,iBAAiB,EAAC,eAAe,EAAC,aAAa,EAAC,eAAe,EAAC,oBAAoB,EAAC,uBAAuB,EAAC,YAAY,EAAC,eAAe,EAAC,aAAa,EAAC,mBAAmB,EAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAChR,UAAU,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;gBACrC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;aACvC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;aACvC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,QAAQ,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aAC/G,IAAI,CAAC,MAAM,CAAC,CAAC;QAChB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;QAEnD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAE5B,4EAA4E;QAC5E,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,CAAC,eAAe,EAAE,CAAC;QAClF,IAAI,aAAa,EAAE,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC5B,CAAC;QAED,sDAAsD;QACtD,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACjD,IAAI,YAAY,EAAE,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3B,CAAC;QAED,0CAA0C;QAC1C,MAAM,KAAK,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;QAChD,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACK,sBAAsB;QAC5B,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB;aACnC,iBAAiB,EAAE;aACnB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;aACvD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;;;;;;YAMC,IAAI,CAAC,MAAM,CAAC,SAAS;oBACb,gBAAgB,CAAC,UAAU;sBACzB,gBAAgB,CAAC,aAAa;;;EAGlD,QAAQ,EAAE,CAAC;IACX,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,WAAmB;QAC5B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,OAAO,GAAG,EAAE,CAAC;YACjB,MAAM,SAAS,GAAqD,EAAE,CAAC;YAEvE,6BAA6B;YAC7B,2FAA2F;YAC3F,4GAA4G;YAC5G,+EAA+E;YAC/E,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAU,EAAE,EAAE;gBACtD,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;oBACjC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC;oBAC1B,IAAI,GAAG,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;wBAC9B,+DAA+D;wBAC/D,OAAO,GAAG,GAAG,CAAC,OAAO;6BAClB,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;6BACrC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;6BACvB,IAAI,CAAC,EAAE,CAAC,CAAC;wBACZ,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;4BAChC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gCAC9B,SAAS,CAAC,IAAI,CAAC;oCACb,IAAI,EAAE,KAAK,CAAC,IAAI;oCAChB,KAAK,EAAE,KAAK,CAAC,KAAK;oCAClB,MAAM,EAAE,IAAI;iCACb,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBACtC,2DAA2D;oBAC3D,WAAW,EAAE,CAAC;oBACd,OAAO,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;gBAClC,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,iCAAiC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC7C,WAAW,EAAE,CAAC;gBACd,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC;IAC9C,CAAC;CACF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: enrich-entities
|
|
3
|
+
description: Proactively suggest enrichment for incomplete entities using context
|
|
4
|
+
loading: eager
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Entity Enrichment
|
|
8
|
+
|
|
9
|
+
When you discover incomplete entities (missing recommended fields), proactively suggest enrichment using contextual inference.
|
|
10
|
+
|
|
11
|
+
## When to Enrich
|
|
12
|
+
|
|
13
|
+
**Proactive discovery:**
|
|
14
|
+
- User asks to "clean up" or "enrich" entities
|
|
15
|
+
- You call `lint_entities` and find incomplete records
|
|
16
|
+
- You fetch an entity and notice missing recommended fields
|
|
17
|
+
|
|
18
|
+
**During normal work:**
|
|
19
|
+
- User asks about a specific entity and you notice gaps
|
|
20
|
+
- You're creating related entities and spot incomplete references
|
|
21
|
+
|
|
22
|
+
## How to Enrich
|
|
23
|
+
|
|
24
|
+
### 1. Discover gaps
|
|
25
|
+
Use `lint_entities` to find incomplete entities:
|
|
26
|
+
```
|
|
27
|
+
lint_entities({ entityType: "project" })
|
|
28
|
+
→ 12 projects missing client, start_date, or end_date
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. Gather context for each incomplete entity
|
|
32
|
+
- **Fetch the entity:** `get_entity({ entityId: "..." })`
|
|
33
|
+
- **Find related entities:** `get_backlinks({ entityId: "..." })`
|
|
34
|
+
- **Search for references:** Look in meeting notes, proposals, briefs
|
|
35
|
+
- **Check memory:** Review past conversations about this entity
|
|
36
|
+
|
|
37
|
+
### 3. Infer missing values from context
|
|
38
|
+
|
|
39
|
+
**Missing client:**
|
|
40
|
+
- Search entity markdown body for `[[client-name]]` wikilinks
|
|
41
|
+
- Check backlinks from meetings, proposals, deals
|
|
42
|
+
- Look for client mentions in related artifacts
|
|
43
|
+
|
|
44
|
+
**Missing dates:**
|
|
45
|
+
- Extract from related meetings (kickoff = start_date)
|
|
46
|
+
- Check proposal expected_start or contract signed_date
|
|
47
|
+
- Look for date mentions in project description
|
|
48
|
+
|
|
49
|
+
**Missing relationships:**
|
|
50
|
+
- Scan for wikilinks in markdown body
|
|
51
|
+
- Check what entities reference this one (backlinks)
|
|
52
|
+
- Infer from entity type (artifact → deliverable → project)
|
|
53
|
+
|
|
54
|
+
### 4. Suggest, don't assume
|
|
55
|
+
Always confirm before updating:
|
|
56
|
+
|
|
57
|
+
> "I notice this project is missing a client. I see Meridian Health mentioned in 3 related meetings and the project brief. Should I add `client: [[meridian-rebrand]]`?"
|
|
58
|
+
|
|
59
|
+
Wait for user confirmation, then call `update_entity`.
|
|
60
|
+
|
|
61
|
+
## Example Workflows
|
|
62
|
+
|
|
63
|
+
**Batch enrichment:**
|
|
64
|
+
```
|
|
65
|
+
User: "Help me fill in missing clients for incomplete projects"
|
|
66
|
+
|
|
67
|
+
You:
|
|
68
|
+
1. lint_entities({ entityType: "project" }) → 8 missing client
|
|
69
|
+
2. For each project:
|
|
70
|
+
- get_entity() → read markdown body
|
|
71
|
+
- get_backlinks() → find meetings, proposals
|
|
72
|
+
- Search for client wikilinks
|
|
73
|
+
- Suggest: "Add client: [[acme]]?" → confirm → update
|
|
74
|
+
3. Report: "Enriched 6/8 projects. 2 need manual review (no clear client in context)."
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Focused enrichment:**
|
|
78
|
+
```
|
|
79
|
+
User: "Fill in missing deal values"
|
|
80
|
+
|
|
81
|
+
You:
|
|
82
|
+
1. lint_entities({ entityType: "deal" }) → 5 deals missing deal_value
|
|
83
|
+
2. For each deal:
|
|
84
|
+
- get_backlinks() → find related proposal
|
|
85
|
+
- get_entity() on proposal → extract fees
|
|
86
|
+
- Suggest: "This deal's proposal shows $50k. Add deal_value: 50000?" → confirm → update
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Inline during work:**
|
|
90
|
+
```
|
|
91
|
+
User: "Show me the Acme project"
|
|
92
|
+
|
|
93
|
+
You:
|
|
94
|
+
1. get_entity({ entityId: "acme-rebrand" })
|
|
95
|
+
2. Notice missing: client, start_date
|
|
96
|
+
3. Get context: search for Acme client entity, check proposal
|
|
97
|
+
4. Suggest inline: "This project is missing a client and start date. I found the Acme client entity and a proposal dated 2026-01-15. Should I add those?"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Guidelines
|
|
101
|
+
|
|
102
|
+
**Do:**
|
|
103
|
+
- Use multiple context sources (backlinks, search, memory, markdown body)
|
|
104
|
+
- Present evidence: "I see X mentioned in 3 meetings"
|
|
105
|
+
- Batch similar fields: "Should I add client and start_date?"
|
|
106
|
+
- Report progress: "Enriched 8/12, 4 need review"
|
|
107
|
+
|
|
108
|
+
**Don't:**
|
|
109
|
+
- Update without confirmation
|
|
110
|
+
- Guess when evidence is weak ("I'm not sure which client this is")
|
|
111
|
+
- Over-enrich — only fill recommended fields that are clearly missing
|
|
112
|
+
- Make up data — if no context exists, say so: "I couldn't find a clear client reference. Would you like to specify it?"
|
|
113
|
+
|
|
114
|
+
## Priority Fields
|
|
115
|
+
|
|
116
|
+
Focus enrichment on high-value semantic fields:
|
|
117
|
+
1. **Relationships** — client, project, deliverable (wikilinks)
|
|
118
|
+
2. **Dates** — start_date, due_date, expected_close
|
|
119
|
+
3. **People** — assignee, decision_makers, attendees
|
|
120
|
+
4. **Values** — deal_value, fees, budget
|
|
121
|
+
|
|
122
|
+
Low-priority (often intentionally omitted):
|
|
123
|
+
- Tags, notes, optional descriptions
|
|
124
|
+
- Status (user may want to set this themselves)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gather-context
|
|
3
|
+
description: Gather full context on named entities before taking action
|
|
4
|
+
loading: eager
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Context Gathering
|
|
8
|
+
|
|
9
|
+
When a user references a specific named entity in their request, gather full context before proceeding:
|
|
10
|
+
|
|
11
|
+
## When to Gather Context
|
|
12
|
+
|
|
13
|
+
User mentions a specific entity by name:
|
|
14
|
+
- "Help me write a proposal for Acme"
|
|
15
|
+
- "Create a deck for the FII10 project"
|
|
16
|
+
- "What's the status of the Meridian Health deliverables?"
|
|
17
|
+
- "Find all open tasks for the Terra Finance project"
|
|
18
|
+
|
|
19
|
+
## What to Gather
|
|
20
|
+
|
|
21
|
+
1. **Fetch the named entity** — use `get_entity` to load the full record
|
|
22
|
+
2. **Pull related entities** — use `get_backlinks` to find connections:
|
|
23
|
+
- For clients: related projects, deals, contacts, proposals
|
|
24
|
+
- For projects: client, deliverables, artifacts, meetings, decisions, tasks
|
|
25
|
+
- For deals: client, contacts, proposal documents
|
|
26
|
+
3. **Check recent activity** — search for recent meetings, decisions, or tasks related to the entity
|
|
27
|
+
4. **Load memory context** — check if there's relevant session memory about this entity
|
|
28
|
+
|
|
29
|
+
## Example Flow
|
|
30
|
+
|
|
31
|
+
User: "Help me write a proposal for Acme"
|
|
32
|
+
|
|
33
|
+
**Before writing anything:**
|
|
34
|
+
1. `get_entity({ repo: "clients", entityType: "client", entityId: "acme" })`
|
|
35
|
+
2. `get_backlinks({ repo: "clients", entityType: "client", entityId: "acme" })`
|
|
36
|
+
3. `search_entities({ query: "Acme", entityTypes: ["deal", "project", "person", "proposal"] })`
|
|
37
|
+
4. Review memory for past Acme conversations
|
|
38
|
+
|
|
39
|
+
**Then proceed** with full context to draft the proposal.
|
|
40
|
+
|
|
41
|
+
## Important
|
|
42
|
+
|
|
43
|
+
- Don't make assumptions about entity details — fetch them first
|
|
44
|
+
- A few seconds gathering context saves minutes of back-and-forth
|
|
45
|
+
- If the entity doesn't exist, offer to create it before proceeding
|
|
46
|
+
- Present a brief context summary to the user before taking action: "I see Acme is a prospect with two past deals and three contacts on file. Let me draft a proposal..."
|
|
@@ -15,12 +15,28 @@ You can sync data from external sources (Linear, Pipedrive, Granola, Obsidian, e
|
|
|
15
15
|
> "You'll need to set up the connector first. Run `studiograph connector add <name>` in your terminal."
|
|
16
16
|
3. **Add the source:** `sync_setup_source({ name: "linear" })` — uses default mappings from built-in definitions when available
|
|
17
17
|
4. **Customize if needed:** Built-in definitions (Pipedrive, Granola, Linear, Asana) provide ready-to-use defaults. To customize, pass `entity_mappings` to `sync_setup_source` to override field maps, add co-location, change target repos, or add status maps. See the `sync-configuration` skill for field map syntax and options.
|
|
18
|
-
5. **No built-in definition?**
|
|
18
|
+
5. **No built-in definition?** Use `sync_inspect_connector` to discover the connector's tools and syncable entity types, then `sync_sample_data` to fetch a sample record and see field shapes. Build `entity_mappings` from the field analysis. See below and the `sync-configuration` skill for the full mapping schema.
|
|
19
19
|
6. **Run the sync:** `sync_run({ sources: ["linear"] })`
|
|
20
20
|
7. **Review staging:** `sync_status` — show the user what will be committed
|
|
21
21
|
8. **Apply on confirmation:** Only call `sync_apply` after the user approves
|
|
22
22
|
9. **Review & commit:** `studiograph review` (interactive diff review with approve/reject per entity), then `studiograph commit` (git commit across all repos)
|
|
23
23
|
|
|
24
|
+
## Building a Config from Scratch (no built-in definition)
|
|
25
|
+
|
|
26
|
+
When a connector has no built-in source definition, use introspection to auto-discover the data model:
|
|
27
|
+
|
|
28
|
+
1. `sync_inspect_connector({ connector: "myservice" })` — lists all tools categorized by purpose, detects syncable entity types with list/get tool pairs
|
|
29
|
+
2. Pick which entity types to sync from the `syncableTypes` results
|
|
30
|
+
3. `sync_sample_data({ connector: "myservice", tool: "list_records" })` — fetches one record and analyzes field shapes. Returns field paths, types, sample values, and suggested field_map entries
|
|
31
|
+
4. Build `entity_mappings` using the field analysis — map source fields to entity schema fields using dot notation for nested fields
|
|
32
|
+
5. `sync_setup_source({ name: "myservice", entity_mappings: [...] })` — save the config
|
|
33
|
+
|
|
34
|
+
**Tips:**
|
|
35
|
+
- `sync_sample_data` auto-sets `limit: 1` — you don't need to pass it
|
|
36
|
+
- Use the `suggestedFieldMap` from the response as a starting point
|
|
37
|
+
- Nested fields use dot notation in field_map keys (e.g. `"org_id.name": "organization"`)
|
|
38
|
+
- Call `sync_sample_data` for each entity type you plan to sync
|
|
39
|
+
|
|
24
40
|
## Modifying an Existing Source
|
|
25
41
|
|
|
26
42
|
When a user asks to adjust, change, or view a source config, **immediately call `sync_list_sources`** to read the current configuration. Do not ask the user to paste the config — you can read it yourself.
|
|
@@ -7,10 +7,18 @@
|
|
|
7
7
|
* - Manage source configs
|
|
8
8
|
*/
|
|
9
9
|
import type { WorkspaceConfig } from '../../core/types.js';
|
|
10
|
+
import type { ConnectorRegistry } from './connector-tools.js';
|
|
11
|
+
/**
|
|
12
|
+
* Mutable holder so the connector registry can be injected after async init.
|
|
13
|
+
* The sync inspect/sample tools gracefully degrade when registry is null.
|
|
14
|
+
*/
|
|
15
|
+
export interface ConnectorRegistryRef {
|
|
16
|
+
registry: ConnectorRegistry | null;
|
|
17
|
+
}
|
|
10
18
|
/**
|
|
11
19
|
* Create sync tools for the agent
|
|
12
20
|
*/
|
|
13
|
-
export declare function createSyncTools(workspacePath: string, workspaceConfig: WorkspaceConfig): {
|
|
21
|
+
export declare function createSyncTools(workspacePath: string, workspaceConfig: WorkspaceConfig, registryRef?: ConnectorRegistryRef): {
|
|
14
22
|
name: string;
|
|
15
23
|
label: string;
|
|
16
24
|
description: string;
|
|
@@ -26,7 +26,8 @@ import { loadUserConfig } from '../../core/user-config.js';
|
|
|
26
26
|
/**
|
|
27
27
|
* Create sync tools for the agent
|
|
28
28
|
*/
|
|
29
|
-
export function createSyncTools(workspacePath, workspaceConfig) {
|
|
29
|
+
export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
30
|
+
const getRegistry = () => registryRef?.registry ?? null;
|
|
30
31
|
return [
|
|
31
32
|
// Run sync pipeline
|
|
32
33
|
{
|
|
@@ -317,6 +318,261 @@ export function createSyncTools(workspacePath, workspaceConfig) {
|
|
|
317
318
|
}
|
|
318
319
|
},
|
|
319
320
|
},
|
|
321
|
+
// ── Connector introspection for sync config building ────────────────────
|
|
322
|
+
// Inspect a connector's tools, categorized for sync
|
|
323
|
+
{
|
|
324
|
+
name: 'sync_inspect_connector',
|
|
325
|
+
label: 'Inspect Connector for Sync',
|
|
326
|
+
description: 'Inspect a connector\'s MCP tools to understand what data types are available for sync. Auto-categorizes tools by purpose (list, get, search, create) and detects syncable entity types with their list/get tool pairs. Use this when building a new source config to understand what the connector offers.',
|
|
327
|
+
parameters: T.Object({
|
|
328
|
+
connector: T.String({ description: 'Connector name (e.g. "pipedrive", "linear", "granola")' }),
|
|
329
|
+
}),
|
|
330
|
+
execute: async (toolCallId, params) => {
|
|
331
|
+
try {
|
|
332
|
+
const reg = getRegistry();
|
|
333
|
+
const tools = reg?.connectors.get(params.connector);
|
|
334
|
+
if (!tools) {
|
|
335
|
+
const available = reg ? [...reg.connectors.keys()] : [];
|
|
336
|
+
return wrapToolResult({
|
|
337
|
+
success: false,
|
|
338
|
+
error: available.length === 0
|
|
339
|
+
? 'No connectors loaded yet. Connectors may still be initializing, or none are configured.'
|
|
340
|
+
: `Connector "${params.connector}" not found`,
|
|
341
|
+
availableConnectors: available,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
// Categorize tools by purpose
|
|
345
|
+
const categories = {
|
|
346
|
+
list: [],
|
|
347
|
+
get: [],
|
|
348
|
+
search: [],
|
|
349
|
+
create: [],
|
|
350
|
+
update: [],
|
|
351
|
+
delete: [],
|
|
352
|
+
other: [],
|
|
353
|
+
};
|
|
354
|
+
for (const tool of tools) {
|
|
355
|
+
const n = tool.localName;
|
|
356
|
+
if (/(?:^list_|_list$|_list_)/.test(n))
|
|
357
|
+
categories.list.push({ name: n, description: tool.description });
|
|
358
|
+
else if (/(?:^get_|_get$|^read_|_read$)/.test(n))
|
|
359
|
+
categories.get.push({ name: n, description: tool.description });
|
|
360
|
+
else if (/(?:^search_|_search$)/.test(n))
|
|
361
|
+
categories.search.push({ name: n, description: tool.description });
|
|
362
|
+
else if (/(?:^create_|_create$)/.test(n))
|
|
363
|
+
categories.create.push({ name: n, description: tool.description });
|
|
364
|
+
else if (/(?:^update_|_update$)/.test(n))
|
|
365
|
+
categories.update.push({ name: n, description: tool.description });
|
|
366
|
+
else if (/(?:^delete_|_delete$|^remove_|_remove$)/.test(n))
|
|
367
|
+
categories.delete.push({ name: n, description: tool.description });
|
|
368
|
+
else
|
|
369
|
+
categories.other.push({ name: n, description: tool.description });
|
|
370
|
+
}
|
|
371
|
+
// Detect syncable entity types (list + optional get pairs)
|
|
372
|
+
const toolNames = new Set(tools.map(t => t.localName));
|
|
373
|
+
const detected = [];
|
|
374
|
+
for (const tool of categories.list) {
|
|
375
|
+
// Extract entity type from tool name
|
|
376
|
+
let sourceType = null;
|
|
377
|
+
const listMatch = tool.name.match(/^list_(.+?)s?$/);
|
|
378
|
+
if (listMatch)
|
|
379
|
+
sourceType = listMatch[1];
|
|
380
|
+
if (!sourceType) {
|
|
381
|
+
const suffixMatch = tool.name.match(/^(.+?)s?_list(?:_|$)/);
|
|
382
|
+
if (suffixMatch)
|
|
383
|
+
sourceType = suffixMatch[1];
|
|
384
|
+
}
|
|
385
|
+
if (!sourceType)
|
|
386
|
+
continue;
|
|
387
|
+
if (detected.some(d => d.source_type === sourceType))
|
|
388
|
+
continue;
|
|
389
|
+
// Find corresponding get tool
|
|
390
|
+
const getVariants = [`get_${sourceType}`, `${sourceType}_get`, `${sourceType}s_get`, `read_${sourceType}`];
|
|
391
|
+
const getTool = getVariants.find(g => toolNames.has(g)) ?? null;
|
|
392
|
+
detected.push({ source_type: sourceType, list_tool: tool.name, get_tool: getTool });
|
|
393
|
+
}
|
|
394
|
+
return wrapToolResult({
|
|
395
|
+
success: true,
|
|
396
|
+
connector: params.connector,
|
|
397
|
+
totalTools: tools.length,
|
|
398
|
+
categories: Object.fromEntries(Object.entries(categories).filter(([_, v]) => v.length > 0)),
|
|
399
|
+
syncableTypes: detected,
|
|
400
|
+
hint: detected.length > 0
|
|
401
|
+
? 'Use sync_sample_data to fetch a sample record from any list tool and see available fields for field_map building.'
|
|
402
|
+
: 'No list tools detected. This connector may not support sync, or tools may use non-standard naming.',
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
return wrapToolResult({
|
|
407
|
+
success: false,
|
|
408
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
// Fetch sample data from a connector to inspect field shapes
|
|
414
|
+
{
|
|
415
|
+
name: 'sync_sample_data',
|
|
416
|
+
label: 'Fetch Sample Data',
|
|
417
|
+
description: 'Fetch a sample record from a connector to inspect its field structure. Calls a list tool with limit 1 and returns the field names, types, nesting, and sample values. Use this to auto-build field_map entries for sync source configs.',
|
|
418
|
+
parameters: T.Object({
|
|
419
|
+
connector: T.String({ description: 'Connector name (e.g. "pipedrive", "linear")' }),
|
|
420
|
+
tool: T.String({ description: 'Tool name to call (e.g. "deals_list", "list_issues")' }),
|
|
421
|
+
arguments: T.Optional(T.Object({}, { additionalProperties: true, description: 'Extra arguments to pass to the tool (limit is auto-set to 1 if the tool accepts it)' })),
|
|
422
|
+
}),
|
|
423
|
+
execute: async (toolCallId, params) => {
|
|
424
|
+
try {
|
|
425
|
+
const reg = getRegistry();
|
|
426
|
+
const tools = reg?.connectors.get(params.connector);
|
|
427
|
+
if (!tools) {
|
|
428
|
+
const available = reg ? [...reg.connectors.keys()] : [];
|
|
429
|
+
return wrapToolResult({
|
|
430
|
+
success: false,
|
|
431
|
+
error: available.length === 0
|
|
432
|
+
? 'No connectors loaded yet. Connectors may still be initializing, or none are configured.'
|
|
433
|
+
: `Connector "${params.connector}" not found`,
|
|
434
|
+
availableConnectors: available,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
const tool = tools.find(t => t.localName === params.tool);
|
|
438
|
+
if (!tool) {
|
|
439
|
+
return wrapToolResult({
|
|
440
|
+
success: false,
|
|
441
|
+
error: `Tool "${params.tool}" not found in ${params.connector}`,
|
|
442
|
+
availableTools: tools.slice(0, 30).map(t => t.localName),
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
// Build arguments — try to limit to 1 record
|
|
446
|
+
const args = { ...params.arguments };
|
|
447
|
+
const schema = tool.parameters;
|
|
448
|
+
const props = schema?.properties || {};
|
|
449
|
+
if ('limit' in props && !args.limit)
|
|
450
|
+
args.limit = 1;
|
|
451
|
+
if ('first' in props && !args.first)
|
|
452
|
+
args.first = 1;
|
|
453
|
+
if ('per_page' in props && !args.per_page)
|
|
454
|
+
args.per_page = 1;
|
|
455
|
+
if ('page_size' in props && !args.page_size)
|
|
456
|
+
args.page_size = 1;
|
|
457
|
+
// Call the tool
|
|
458
|
+
const result = await tool.execute(toolCallId, args);
|
|
459
|
+
const text = result?.content?.[0]?.text ?? '';
|
|
460
|
+
// Parse the response
|
|
461
|
+
let data;
|
|
462
|
+
try {
|
|
463
|
+
data = JSON.parse(text);
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
// Some tools return double-wrapped content
|
|
467
|
+
try {
|
|
468
|
+
const outer = JSON.parse(text);
|
|
469
|
+
if (outer.content?.[0]?.text) {
|
|
470
|
+
data = JSON.parse(outer.content[0].text);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
return wrapToolResult({
|
|
475
|
+
success: true,
|
|
476
|
+
rawResponse: text.slice(0, 3000),
|
|
477
|
+
note: 'Response is not JSON. Showing raw text for manual inspection.',
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
// Extract the first record from common response shapes
|
|
482
|
+
let record = null;
|
|
483
|
+
if (Array.isArray(data)) {
|
|
484
|
+
record = data[0];
|
|
485
|
+
}
|
|
486
|
+
else if (data?.data && Array.isArray(data.data)) {
|
|
487
|
+
record = data.data[0];
|
|
488
|
+
}
|
|
489
|
+
else if (data?.items && Array.isArray(data.items)) {
|
|
490
|
+
record = data.items[0];
|
|
491
|
+
}
|
|
492
|
+
else if (data?.results && Array.isArray(data.results)) {
|
|
493
|
+
record = data.results[0];
|
|
494
|
+
}
|
|
495
|
+
else if (data?.nodes && Array.isArray(data.nodes)) {
|
|
496
|
+
record = data.nodes[0];
|
|
497
|
+
}
|
|
498
|
+
else if (typeof data === 'object' && data !== null && !Array.isArray(data)) {
|
|
499
|
+
// Might be a single record response
|
|
500
|
+
record = data;
|
|
501
|
+
}
|
|
502
|
+
if (!record) {
|
|
503
|
+
return wrapToolResult({
|
|
504
|
+
success: true,
|
|
505
|
+
note: 'No records returned. The source may be empty or the tool may need different arguments.',
|
|
506
|
+
responseShape: typeof data,
|
|
507
|
+
responseKeys: data && typeof data === 'object' ? Object.keys(data) : [],
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
// Analyze field structure
|
|
511
|
+
const analyzeFields = (obj, prefix = '') => {
|
|
512
|
+
const fields = [];
|
|
513
|
+
if (!obj || typeof obj !== 'object')
|
|
514
|
+
return fields;
|
|
515
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
516
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
517
|
+
const type = value === null ? 'null'
|
|
518
|
+
: Array.isArray(value) ? `array(${value.length})`
|
|
519
|
+
: typeof value;
|
|
520
|
+
// Truncate long strings for display
|
|
521
|
+
let sample = value;
|
|
522
|
+
if (typeof value === 'string' && value.length > 100) {
|
|
523
|
+
sample = value.slice(0, 100) + '...';
|
|
524
|
+
}
|
|
525
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
526
|
+
fields.push({ path, type: 'object', sample: `{${Object.keys(value).join(', ')}}` });
|
|
527
|
+
// Recurse one level into objects
|
|
528
|
+
fields.push(...analyzeFields(value, path));
|
|
529
|
+
}
|
|
530
|
+
else if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'object') {
|
|
531
|
+
fields.push({ path, type: `array(${value.length})`, sample: `[{${Object.keys(value[0]).join(', ')}}]` });
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
fields.push({ path, type, sample });
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return fields;
|
|
538
|
+
};
|
|
539
|
+
const fields = analyzeFields(record);
|
|
540
|
+
// Suggest field_map entries for common entity fields
|
|
541
|
+
const topLevelKeys = Object.keys(record);
|
|
542
|
+
const suggestions = {};
|
|
543
|
+
const nameFields = ['title', 'name', 'subject', 'summary'];
|
|
544
|
+
const statusFields = ['status', 'state', 'stage'];
|
|
545
|
+
const dateFields = ['created_at', 'createdAt', 'date', 'start_date', 'due_date', 'dueDate'];
|
|
546
|
+
const descFields = ['description', 'content', 'body', 'notes', 'note'];
|
|
547
|
+
for (const key of topLevelKeys) {
|
|
548
|
+
if (nameFields.includes(key))
|
|
549
|
+
suggestions[key] = 'name';
|
|
550
|
+
else if (statusFields.includes(key))
|
|
551
|
+
suggestions[key] = 'status';
|
|
552
|
+
else if (dateFields.includes(key))
|
|
553
|
+
suggestions[key] = 'date (use date-iso transform)';
|
|
554
|
+
else if (descFields.includes(key))
|
|
555
|
+
suggestions[key] = 'description (or use as content_from)';
|
|
556
|
+
}
|
|
557
|
+
return wrapToolResult({
|
|
558
|
+
success: true,
|
|
559
|
+
connector: params.connector,
|
|
560
|
+
tool: params.tool,
|
|
561
|
+
fieldCount: fields.length,
|
|
562
|
+
fields,
|
|
563
|
+
topLevelKeys,
|
|
564
|
+
suggestedFieldMap: Object.keys(suggestions).length > 0 ? suggestions : undefined,
|
|
565
|
+
hint: 'Use these field paths in field_map when configuring sync_setup_source. Nested fields use dot notation (e.g. "org_id.name": "organization").',
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
return wrapToolResult({
|
|
570
|
+
success: false,
|
|
571
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
},
|
|
320
576
|
// ── Enrich tools ──────────────────────────────────────────────────────────
|
|
321
577
|
// Run enrichment
|
|
322
578
|
{
|