fuli-context 0.7.4-beta.3 → 0.7.5
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/README.md +77 -6
- package/README.zh-CN.md +69 -6
- package/compose.graphiti.yml +6 -6
- package/dist/web/assets/AboutPage-ByCUor-j.js +1 -0
- package/dist/web/assets/ConnectionsPage-DkdkZ40Q.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-DSe3Gwep.js +1 -0
- package/dist/web/assets/KnowledgeInspector-CYAjAb9J.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-CV4F54R_.js +1 -0
- package/dist/web/assets/KnowledgePage-vYYXipOi.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-z4u5mXOG.js +4 -0
- package/dist/web/assets/OverviewPage-BWOfeS6k.js +1 -0
- package/dist/web/assets/PersonalProfilePage-c3w4-h7a.js +1 -0
- package/dist/web/assets/PersonalProjectsPage-B7AlLEwf.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-CgftpIPB.css +1 -0
- package/dist/web/assets/ProjectAgentsPage-DTHcL_ox.js +11 -0
- package/dist/web/assets/PublicProjectsPage-DdH0oGB3.js +1 -0
- package/dist/web/assets/ReviewPage-BYIpcIHG.js +1 -0
- package/dist/web/assets/SearchableSelect-Dz13ClQb.js +1 -0
- package/dist/web/assets/SettingsPage-2VkbXgZi.js +1 -0
- package/dist/web/assets/SettingsPage-CwZp2ka4.css +1 -0
- package/dist/web/assets/WritingTastePage-BOPQZuva.js +1 -0
- package/dist/web/assets/{console-D_2zC4lm.js → console-BlAhujsH.js} +1 -1
- package/dist/web/assets/{conversation-launcher-settings-DQmMH2j7.js → conversation-launcher-settings-DTYxiLJt.js} +1 -1
- package/dist/web/assets/i18n-Ci3heuiL.js +9 -0
- package/dist/web/assets/{identity-DmGcY3Y6.js → identity-4_-v6cB7.js} +1 -1
- package/dist/web/assets/index-BnH5mcZx.css +1 -0
- package/dist/web/assets/index-C67Q0JY2.js +2 -0
- package/dist/web/assets/{model-CVoOdRsL.js → model-yG0YqUyZ.js} +1 -1
- package/dist/web/assets/{useApi-CROJJdhE-CBNg4CdH.js → useApi-CROJJdhE-twhdZArA.js} +1 -1
- package/dist/web/assets/vue-router-C-wot_Di.js +1 -0
- package/dist/web/index.html +6 -6
- package/graph-provider/fuli_graph/app.py +8 -0
- package/graph-provider/fuli_graph/collaboration_context.py +69 -6
- package/graph-provider/fuli_graph/knowledge_search.py +84 -5
- package/graph-provider/fuli_graph/model_validation.py +130 -0
- package/graph-provider/fuli_graph/models.py +24 -5
- package/graph-provider/fuli_graph/project_agent_access.py +54 -0
- package/graph-provider/fuli_graph/project_agent_executor_models.py +635 -0
- package/graph-provider/fuli_graph/project_agent_models.py +278 -0
- package/graph-provider/fuli_graph/project_agent_routes.py +597 -0
- package/graph-provider/fuli_graph/project_agent_task_models.py +542 -0
- package/graph-provider/fuli_graph/runtime.py +259 -0
- package/graph-provider/fuli_graph/search_projection.py +3 -0
- package/graph-provider/fuli_graph/store.py +6 -0
- package/graph-provider/fuli_graph/store_knowledge.py +62 -9
- package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +756 -0
- package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +601 -0
- package/graph-provider/fuli_graph/store_project_agent_executors.py +1087 -0
- package/graph-provider/fuli_graph/store_project_agent_task_reads.py +458 -0
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +699 -0
- package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +409 -0
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +1144 -0
- package/graph-provider/fuli_graph/store_project_agents.py +965 -0
- package/graph-provider/pyproject.toml +2 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/skills/capturing-session-knowledge/SKILL.md +39 -0
- package/src/adaptive-runtime/executor-pool.js +127 -0
- package/src/adaptive-runtime/graph-services.js +166 -0
- package/src/adaptive-runtime/lease-client.js +335 -0
- package/src/adaptive-runtime/runtime-broker.js +318 -0
- package/src/adaptive-runtime/settings.js +111 -0
- package/src/adaptive-runtime/state.js +74 -0
- package/src/agent-tools/graph-definitions.js +396 -0
- package/src/agent-tools/graph-handlers.js +61 -0
- package/src/agent-tools/project-agent-definitions.js +307 -0
- package/src/backup/graph-backup.js +289 -0
- package/src/backup/identity-reconciliation.js +208 -0
- package/src/backup/runtime-adapters.js +269 -0
- package/src/cli/command-registry.js +6 -2
- package/src/cli/graph-data-command.js +112 -0
- package/src/cli/local-runtime-command.js +16 -2
- package/src/cli/setup-command.js +19 -3
- package/src/cli/update-command.js +4 -0
- package/src/cli.js +6 -0
- package/src/graphiti/collaboration-preference-projection.js +29 -1
- package/src/graphiti/collaboration-preference-workflow.js +121 -0
- package/src/graphiti/federated-application.js +53 -90
- package/src/graphiti/project-agent-control-plane.js +263 -0
- package/src/graphiti/project-agent-mapping.js +1003 -0
- package/src/graphiti/project-agent-workflows.js +557 -0
- package/src/graphiti/provider-client.js +270 -1
- package/src/http/api-router.js +63 -9
- package/src/http/graph-api-router.js +278 -0
- package/src/local-runtime/lifecycle.js +46 -10
- package/src/mcp/context-resources.js +15 -6
- package/src/mcp/create-mcp-server.js +51 -16
- package/src/mcp/instructions.js +7 -5
- package/src/mcp/runtime.js +17 -5
- package/src/mcp/session-id.js +38 -1
- package/src/mcp/tool-annotations.js +69 -0
- package/src/mcp-server.js +23 -6
- package/src/native-runtime/runtime.js +717 -0
- package/src/server.js +6 -2
- package/src/setup/agent-installation-status.js +7 -1
- package/src/setup/agents.js +3 -1
- package/src/setup/claude-code-config.js +3 -1
- package/src/setup/codex-bootstrap.js +11 -10
- package/src/setup/codex-config.js +7 -1
- package/src/setup/cursor-config.js +3 -1
- package/src/setup/graph-runtime.js +158 -13
- package/src/setup/neo4j-memory-profile.js +43 -0
- package/src/setup/options.js +38 -2
- package/src/setup/paths.js +14 -0
- package/src/setup/setup.js +37 -1
- package/src/system/resource-monitor.js +181 -16
- package/src/system/runtime-settings.js +10 -1
- package/src/system/system-service.js +27 -2
- package/dist/web/assets/AboutPage-Dpf5fRWv.js +0 -1
- package/dist/web/assets/ConnectionsPage-D21aUDCP.js +0 -1
- package/dist/web/assets/KnowledgeEditDialog-u7lpfN3j.js +0 -1
- package/dist/web/assets/KnowledgeInspector-k4xnHtXd.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-Bdj7Rn84.js +0 -1
- package/dist/web/assets/KnowledgePage-UHVAbC1W.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-Lq3d-MeC.js +0 -4
- package/dist/web/assets/OverviewPage-CycAgA1V.js +0 -1
- package/dist/web/assets/PersonalProfilePage-U9oIV5FT.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-C5RpXKcA.js +0 -1
- package/dist/web/assets/PublicProjectsPage-DiWxm35E.js +0 -1
- package/dist/web/assets/ReviewPage-jxRfGSJK.js +0 -1
- package/dist/web/assets/SearchableSelect-B3-5IPup.js +0 -1
- package/dist/web/assets/SettingsPage-BqfGDOho.js +0 -1
- package/dist/web/assets/SettingsPage-CAfz4qiV.css +0 -1
- package/dist/web/assets/WritingTastePage-BJxhMqJR.js +0 -1
- package/dist/web/assets/i18n-CwqXDI1C.js +0 -5
- package/dist/web/assets/index-IUGLt4lG.js +0 -2
- package/dist/web/assets/index-X2j29j8i.css +0 -1
- package/dist/web/assets/vue-router-CWSsUUio.js +0 -1
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
stopGraphProviders
|
|
8
8
|
} from '../setup/graph-runtime.js';
|
|
9
9
|
import { readJsonFile } from '../storage/json-file.js';
|
|
10
|
+
import { readAdaptiveRuntimeSettings } from '../adaptive-runtime/settings.js';
|
|
11
|
+
import { readAdaptiveRuntimeState } from '../adaptive-runtime/state.js';
|
|
10
12
|
import {
|
|
11
13
|
DEFAULT_RUNTIME_SETTINGS,
|
|
12
14
|
managedProviderUrls
|
|
@@ -28,6 +30,7 @@ export async function startLocalRuntime(input, dependencies = {}) {
|
|
|
28
30
|
port: input.port,
|
|
29
31
|
lan: input.lan === true,
|
|
30
32
|
runtimeSettings,
|
|
33
|
+
previousRuntimeMode: input.previousRuntimeMode,
|
|
31
34
|
personalOnly: !managesDevelopmentWorkspace,
|
|
32
35
|
buildProviders,
|
|
33
36
|
noStart: false,
|
|
@@ -51,11 +54,14 @@ export async function stopLocalRuntime(input, dependencies = {}) {
|
|
|
51
54
|
const managesDevelopmentWorkspace = state?.managedProviders?.includes(
|
|
52
55
|
'development-workspace'
|
|
53
56
|
) || hasManagedDevelopmentWorkspace(config, runtimeSettings);
|
|
57
|
+
const activeRuntimeMode = state?.runtimeSettings?.graphRuntimeMode ??
|
|
58
|
+
runtimeSettings.graphRuntimeMode;
|
|
54
59
|
|
|
55
60
|
let providers = 'not_initialized';
|
|
56
61
|
if (deps.fileExists(input.paths.graphEnvPath)) {
|
|
57
|
-
deps.stopProviders(input.paths, input.paths.graphEnvPath, {
|
|
58
|
-
personalOnly: !managesDevelopmentWorkspace
|
|
62
|
+
await deps.stopProviders(input.paths, input.paths.graphEnvPath, {
|
|
63
|
+
personalOnly: !managesDevelopmentWorkspace,
|
|
64
|
+
runtimeMode: activeRuntimeMode
|
|
59
65
|
});
|
|
60
66
|
providers = 'stopped';
|
|
61
67
|
}
|
|
@@ -70,11 +76,14 @@ export async function stopLocalRuntime(input, dependencies = {}) {
|
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
export async function restartLocalRuntime(input, dependencies = {}) {
|
|
79
|
+
const deps = lifecycleDependencies(dependencies);
|
|
80
|
+
const previousRuntimeMode = deps.readState(input.paths.graphRuntimeStatePath)
|
|
81
|
+
?.runtimeSettings?.graphRuntimeMode;
|
|
73
82
|
const stopped = await stopLocalRuntime(input, dependencies);
|
|
74
83
|
if (stopped.status === 'partial') {
|
|
75
84
|
throw new Error('Could not safely verify the existing local UI process; restart was refused.');
|
|
76
85
|
}
|
|
77
|
-
const started = await startLocalRuntime(input, dependencies);
|
|
86
|
+
const started = await startLocalRuntime({ ...input, previousRuntimeMode }, dependencies);
|
|
78
87
|
return { stopped, ...started, status: 'restarted' };
|
|
79
88
|
}
|
|
80
89
|
|
|
@@ -90,19 +99,34 @@ export async function inspectLocalRuntime(input, dependencies = {}) {
|
|
|
90
99
|
state.pid,
|
|
91
100
|
state.version
|
|
92
101
|
);
|
|
102
|
+
const adaptiveSettings = deps.readAdaptiveSettings(pathsValue(
|
|
103
|
+
input.paths.adaptiveRuntimeSettingsPath
|
|
104
|
+
));
|
|
105
|
+
const adaptiveState = adaptiveSettings.enabled
|
|
106
|
+
? deps.readAdaptiveState(pathsValue(input.paths.adaptiveRuntimeStatePath))
|
|
107
|
+
: null;
|
|
108
|
+
const intentionallySleeping = adaptiveSettings.enabled &&
|
|
109
|
+
['provider-sleeping', 'sleeping'].includes(adaptiveState?.stage);
|
|
93
110
|
const managedUrls = managedProviderUrls(runtimeSettings);
|
|
94
111
|
const personalUrl = config?.personal?.providerUrl ?? managedUrls.personal;
|
|
95
112
|
const personal = config
|
|
96
|
-
?
|
|
113
|
+
? intentionallySleeping
|
|
114
|
+
? { url: personalUrl, status: 'sleeping' }
|
|
115
|
+
: await deps.providerHealth(personalUrl)
|
|
97
116
|
: { url: personalUrl, status: 'not_configured' };
|
|
98
|
-
const workspaces = await Promise.all((config?.workspaces ?? []).map(async (workspace) =>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
117
|
+
const workspaces = await Promise.all((config?.workspaces ?? []).map(async (workspace) => {
|
|
118
|
+
const managedDevelopment = isManagedDevelopmentUrl(workspace, runtimeSettings);
|
|
119
|
+
return {
|
|
120
|
+
...(intentionallySleeping && managedDevelopment
|
|
121
|
+
? { url: workspace.providerUrl, status: 'sleeping' }
|
|
122
|
+
: await deps.providerHealth(workspace.providerUrl)),
|
|
123
|
+
managedDevelopment
|
|
124
|
+
};
|
|
125
|
+
}));
|
|
102
126
|
|
|
103
127
|
let status = 'stopped';
|
|
104
128
|
if (!config && !state) status = 'not_configured';
|
|
105
|
-
else if (consoleReady && personal.status
|
|
129
|
+
else if (consoleReady && ['ready', 'sleeping'].includes(personal.status)) status = 'running';
|
|
106
130
|
else if (processAlive || personal.status === 'ready') status = 'degraded';
|
|
107
131
|
|
|
108
132
|
return {
|
|
@@ -120,6 +144,10 @@ export async function inspectLocalRuntime(input, dependencies = {}) {
|
|
|
120
144
|
configured: workspaces.length > 0,
|
|
121
145
|
status: publicProviderStatus(workspaces),
|
|
122
146
|
providers: workspaces
|
|
147
|
+
},
|
|
148
|
+
adaptiveRuntime: {
|
|
149
|
+
enabled: adaptiveSettings.enabled,
|
|
150
|
+
stage: adaptiveSettings.enabled ? adaptiveState?.stage ?? 'unknown' : 'always-on'
|
|
123
151
|
}
|
|
124
152
|
};
|
|
125
153
|
}
|
|
@@ -162,6 +190,10 @@ function lifecycleDependencies(overrides) {
|
|
|
162
190
|
stopProviders: stopGraphProviders,
|
|
163
191
|
consoleHealth: checkLocalConsoleHealth,
|
|
164
192
|
providerHealth,
|
|
193
|
+
readAdaptiveSettings: (path) => path
|
|
194
|
+
? readAdaptiveRuntimeSettings(path)
|
|
195
|
+
: { enabled: false },
|
|
196
|
+
readAdaptiveState: (path) => path ? readAdaptiveRuntimeState(path) : null,
|
|
165
197
|
isProcessAlive,
|
|
166
198
|
stopProcess,
|
|
167
199
|
waitForExit,
|
|
@@ -173,6 +205,10 @@ function lifecycleDependencies(overrides) {
|
|
|
173
205
|
};
|
|
174
206
|
}
|
|
175
207
|
|
|
208
|
+
function pathsValue(value) {
|
|
209
|
+
return typeof value === 'string' && value ? value : null;
|
|
210
|
+
}
|
|
211
|
+
|
|
176
212
|
function safeReadState(path) {
|
|
177
213
|
try {
|
|
178
214
|
return readJsonFile(path, null);
|
|
@@ -242,7 +278,7 @@ function isLoopbackConsoleUrl(value) {
|
|
|
242
278
|
|
|
243
279
|
function publicProviderStatus(workspaces) {
|
|
244
280
|
if (!workspaces.length) return 'not_connected';
|
|
245
|
-
const ready = workspaces.filter(({ status }) =>
|
|
281
|
+
const ready = workspaces.filter(({ status }) => ['ready', 'sleeping'].includes(status)).length;
|
|
246
282
|
if (ready === workspaces.length) return 'ready';
|
|
247
283
|
return ready > 0 ? 'degraded' : 'unavailable';
|
|
248
284
|
}
|
|
@@ -6,7 +6,9 @@ const RESOURCE_MIME_TYPE = 'text/markdown';
|
|
|
6
6
|
const MAX_PROJECT_PURPOSE_LENGTH = 240;
|
|
7
7
|
const MAX_RESOURCE_TEXT_BYTES = 32 * 1024;
|
|
8
8
|
|
|
9
|
-
export function registerFuliContextResources(server, app
|
|
9
|
+
export function registerFuliContextResources(server, app, {
|
|
10
|
+
withRuntimeLease = (_owner, operation) => operation()
|
|
11
|
+
} = {}) {
|
|
10
12
|
server.registerResource(
|
|
11
13
|
'FULI global taste',
|
|
12
14
|
GLOBAL_TASTE_RESOURCE_URI,
|
|
@@ -15,13 +17,17 @@ export function registerFuliContextResources(server, app) {
|
|
|
15
17
|
description: 'The user\'s current evidence-backed global taste and working preferences.',
|
|
16
18
|
mimeType: RESOURCE_MIME_TYPE
|
|
17
19
|
},
|
|
18
|
-
(uri) =>
|
|
20
|
+
(uri) => withRuntimeLease(
|
|
21
|
+
'mcp-resource:global-taste',
|
|
22
|
+
() => readGlobalTasteResource(app, uri)
|
|
23
|
+
)
|
|
19
24
|
);
|
|
20
25
|
|
|
21
26
|
const projectResources = new ResourceTemplate(PROJECT_RESOURCE_TEMPLATE, {
|
|
22
|
-
list:
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
list: () => withRuntimeLease(
|
|
28
|
+
'mcp-resource:list-projects',
|
|
29
|
+
async () => ({ resources: await listPersonalProjectResources(app) })
|
|
30
|
+
)
|
|
25
31
|
});
|
|
26
32
|
server.registerResource(
|
|
27
33
|
'fuli-personal-project',
|
|
@@ -31,7 +37,10 @@ export function registerFuliContextResources(server, app) {
|
|
|
31
37
|
description: 'Select one exact local FULI personal project for this task.',
|
|
32
38
|
mimeType: RESOURCE_MIME_TYPE
|
|
33
39
|
},
|
|
34
|
-
(uri, variables) =>
|
|
40
|
+
(uri, variables) => withRuntimeLease(
|
|
41
|
+
'mcp-resource:project',
|
|
42
|
+
() => readPersonalProjectResource(app, uri, variables)
|
|
43
|
+
)
|
|
35
44
|
);
|
|
36
45
|
}
|
|
37
46
|
|
|
@@ -19,7 +19,8 @@ import { jsonSchemaToZod, openObjectSchema } from './tool-schema.js';
|
|
|
19
19
|
import {
|
|
20
20
|
mcpHostSessionId,
|
|
21
21
|
nativeCodexThreadId,
|
|
22
|
-
normalizeAgentSessionInput
|
|
22
|
+
normalizeAgentSessionInput,
|
|
23
|
+
normalizeMcpSourceApplication
|
|
23
24
|
} from './session-id.js';
|
|
24
25
|
|
|
25
26
|
const TOOL_RESULT_LIMIT_BYTES = Object.freeze({
|
|
@@ -33,6 +34,24 @@ const TOOL_RESULT_LIMIT_BYTES = Object.freeze({
|
|
|
33
34
|
discover_personal_global_preference_candidates: 32 * 1024,
|
|
34
35
|
preview_personal_global_preference_decision: 32 * 1024,
|
|
35
36
|
list_personal_projects: 32 * 1024,
|
|
37
|
+
list_project_agents: 32 * 1024,
|
|
38
|
+
get_project_agent: 32 * 1024,
|
|
39
|
+
list_project_agent_assignments: 32 * 1024,
|
|
40
|
+
get_project_agent_context: 64 * 1024,
|
|
41
|
+
coordinate_project_agent_task: 256 * 1024,
|
|
42
|
+
acquire_runtime_lease: 4 * 1024,
|
|
43
|
+
refresh_runtime_lease: 4 * 1024,
|
|
44
|
+
release_runtime_lease: 4 * 1024,
|
|
45
|
+
view_project_agent_task: 64 * 1024,
|
|
46
|
+
view_project_agent_activity: 64 * 1024,
|
|
47
|
+
list_project_agent_recruitments: 32 * 1024,
|
|
48
|
+
list_executors: 32 * 1024,
|
|
49
|
+
get_executor: 32 * 1024,
|
|
50
|
+
preflight_executor: 32 * 1024,
|
|
51
|
+
record_project_agent_executor_actual: 32 * 1024,
|
|
52
|
+
list_executor_routing_rules: 32 * 1024,
|
|
53
|
+
get_executor_routing_rule: 32 * 1024,
|
|
54
|
+
list_project_agent_routing_learning: 64 * 1024,
|
|
36
55
|
list_knowledge_review_candidates: 32 * 1024,
|
|
37
56
|
list_workflow_candidates: 32 * 1024,
|
|
38
57
|
recommend_next_workflow_steps: 32 * 1024
|
|
@@ -40,7 +59,12 @@ const TOOL_RESULT_LIMIT_BYTES = Object.freeze({
|
|
|
40
59
|
|
|
41
60
|
export function createMcpServer(
|
|
42
61
|
app,
|
|
43
|
-
{
|
|
62
|
+
{
|
|
63
|
+
env = process.env,
|
|
64
|
+
clock = () => new Date(),
|
|
65
|
+
sourceApplication = nativeCodexThreadId(env) ? 'codex' : 'other',
|
|
66
|
+
withRuntimeLease = (_owner, operation) => operation()
|
|
67
|
+
} = {}
|
|
44
68
|
) {
|
|
45
69
|
const server = new McpServer(
|
|
46
70
|
{ name: 'fuli', version: FULI_VERSION },
|
|
@@ -48,15 +72,20 @@ export function createMcpServer(
|
|
|
48
72
|
);
|
|
49
73
|
|
|
50
74
|
const nativeThreadId = nativeCodexThreadId(env);
|
|
75
|
+
const authoritativeSourceApplication = normalizeMcpSourceApplication(
|
|
76
|
+
sourceApplication
|
|
77
|
+
);
|
|
51
78
|
const tools = createToolMap(
|
|
52
79
|
app,
|
|
53
80
|
createProjectActionPreviewTokens(),
|
|
54
81
|
nativeThreadId,
|
|
55
82
|
mcpHostSessionId(env),
|
|
56
|
-
clock
|
|
83
|
+
clock,
|
|
84
|
+
authoritativeSourceApplication,
|
|
85
|
+
withRuntimeLease
|
|
57
86
|
);
|
|
58
87
|
for (const tool of tools.values()) registerTool(server, tool);
|
|
59
|
-
registerFuliContextResources(server, app);
|
|
88
|
+
registerFuliContextResources(server, app, { withRuntimeLease });
|
|
60
89
|
registerCallHandler(server, tools);
|
|
61
90
|
return server;
|
|
62
91
|
}
|
|
@@ -66,24 +95,30 @@ function createToolMap(
|
|
|
66
95
|
projectActionPreviews,
|
|
67
96
|
nativeThreadId,
|
|
68
97
|
hostSessionId,
|
|
69
|
-
clock
|
|
98
|
+
clock,
|
|
99
|
+
sourceApplication,
|
|
100
|
+
withRuntimeLease
|
|
70
101
|
) {
|
|
71
102
|
const commonKnowledgePreviews = createCommonKnowledgePreviewTokens();
|
|
72
103
|
return new Map(listAgentTools().map((definition) => [definition.name, {
|
|
73
104
|
definition,
|
|
74
105
|
schema: jsonSchemaToZod(definition.inputSchema),
|
|
75
|
-
invoke: (input) =>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
invoke: (input) => withRuntimeLease(
|
|
107
|
+
`mcp-tool:${definition.name}`,
|
|
108
|
+
() => invokeAgentTool(
|
|
109
|
+
app,
|
|
79
110
|
definition.name,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
111
|
+
normalizeAgentSessionInput(
|
|
112
|
+
definition.name,
|
|
113
|
+
input,
|
|
114
|
+
nativeThreadId,
|
|
115
|
+
hostSessionId,
|
|
116
|
+
clock,
|
|
117
|
+
sourceApplication
|
|
118
|
+
),
|
|
119
|
+
projectActionPreviews,
|
|
120
|
+
commonKnowledgePreviews
|
|
121
|
+
)
|
|
87
122
|
)
|
|
88
123
|
}]));
|
|
89
124
|
}
|
package/src/mcp/instructions.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export const MCP_INSTRUCTIONS = [
|
|
2
|
-
'Each user task: hook-provided task context
|
|
3
|
-
'Before asking
|
|
4
|
-
'Before saying unknown
|
|
5
|
-
'
|
|
6
|
-
'
|
|
2
|
+
'Each user task: hook-provided task context via begin_task_context; otherwise before other tools/answer call exactly get_collaboration_preferences(projectPath=cwd taskPrompt=current user request) as fallback; never substitute a project action. Apply all effective_preferences: personal-global everywhere; matched project, authorized inheritable parent. get_user_taste_skill never replaces a user-authored Skill. Resolve deferred_conflict; never guess personalProjectId. Writes use actual payload; final text not compliance.',
|
|
3
|
+
'Before asking for stable project fact or method inspect task_knowledge_recall. On miss search_current_project_knowledge with focused action, artifact, target-system, or identifier queries; never use the whole conversational request as the only query. Search active child first, then authorized inheritable parent (PART_OF/USES_KNOWLEDGE_FROM); local_only/RELATED_TO never inherit.',
|
|
4
|
+
'Before saying unknown call search_knowledge_graph; exact IDs for extra projects. RELATED_TO suggests; ask. all_local_confirmed only after consent; rg safe current repo/workspace; Never scan outside it. monitoring/Git MCP; search_connected_knowledge; agent_decide response-only.',
|
|
5
|
+
'record_decision_trace; failures record_knowledge_feedback. Batch durable confirmed knowledge: capture_session_knowledge; no secrets. checkpoint_task_knowledge: capture_candidates or retain_nothing; record_knowledge_usage.',
|
|
6
|
+
'Team: coordinate_project_agent_task gives isolated contexts; Fuli never spawns. Host: acquire_runtime_lease, start workers, report activity/executor, release_runtime_lease in finally.',
|
|
7
|
+
'Non-empty Provider executionSummary: one row/worker: occupation emoji/label, actual executor/sourceApplication, work summary, workerStatus/status. Empty/absent executionSummary: omit. Configured/allowed/available are not evidence.',
|
|
8
|
+
'Terminal-safe Markdown; never wrap in HTML. A match is a candidate only. If it supports the answer, MUST begin sourceMarker.leadMarkdown and append sourceMarker.markdown; otherwise use noMatchSourceMarker (empty). Keep unchanged.'
|
|
7
9
|
].join(' ');
|
package/src/mcp/runtime.js
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
bindRuntimeLeaseAgentTools,
|
|
5
|
+
createRuntimeLeaseClient
|
|
6
|
+
} from '../adaptive-runtime/lease-client.js';
|
|
3
7
|
import { openFederatedGraphApplication } from '../graphiti/federated-application.js';
|
|
4
8
|
import { createMcpServer } from './create-mcp-server.js';
|
|
5
9
|
|
|
6
|
-
export async function runStdio({ runtimeConfigPath }) {
|
|
10
|
+
export async function runStdio({ runtimeConfigPath, sourceApplication }) {
|
|
7
11
|
const app = openFederatedGraphApplication({ runtimeConfigPath });
|
|
8
|
-
const
|
|
12
|
+
const leaseClient = createRuntimeLeaseClient({ runtimeConfigPath });
|
|
13
|
+
bindRuntimeLeaseAgentTools(app, leaseClient);
|
|
14
|
+
const server = createServerOrClose(app, createMcpServer, {
|
|
15
|
+
sourceApplication,
|
|
16
|
+
withRuntimeLease: leaseClient.withGraphLease
|
|
17
|
+
});
|
|
9
18
|
const transport = new StdioServerTransport();
|
|
10
19
|
const signalHandlers = new Map();
|
|
11
20
|
const close = createCloseOnce({
|
|
12
21
|
closeServer: () => server.close(),
|
|
13
|
-
closeApplication: () =>
|
|
22
|
+
closeApplication: async () => {
|
|
23
|
+
await leaseClient.close();
|
|
24
|
+
return app.close();
|
|
25
|
+
},
|
|
14
26
|
afterClose: () => removeHandlers(signalHandlers)
|
|
15
27
|
});
|
|
16
28
|
const quietClose = createQuietCloser(close, () => { process.exitCode = 1; });
|
|
@@ -31,9 +43,9 @@ export async function runStdio({ runtimeConfigPath }) {
|
|
|
31
43
|
}
|
|
32
44
|
}
|
|
33
45
|
|
|
34
|
-
export function createServerOrClose(app, factory = createMcpServer) {
|
|
46
|
+
export function createServerOrClose(app, factory = createMcpServer, options) {
|
|
35
47
|
try {
|
|
36
|
-
return factory(app);
|
|
48
|
+
return factory(app, options);
|
|
37
49
|
} catch (error) {
|
|
38
50
|
void app.close();
|
|
39
51
|
throw error;
|
package/src/mcp/session-id.js
CHANGED
|
@@ -2,6 +2,17 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
|
|
3
3
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4
4
|
const WORKFLOW_OBSERVATION_TOOL = 'record_workflow_transition_observation';
|
|
5
|
+
const PROJECT_AGENT_SOURCE_TOOLS = new Set([
|
|
6
|
+
'create_project_agent_assignment',
|
|
7
|
+
'replace_project_agent_assignment',
|
|
8
|
+
'coordinate_project_agent_task',
|
|
9
|
+
'submit_project_agent_task',
|
|
10
|
+
'get_project_agent_context',
|
|
11
|
+
'record_project_agent_task_activity',
|
|
12
|
+
'preflight_executor',
|
|
13
|
+
'report_executor_health',
|
|
14
|
+
'record_project_agent_executor_actual'
|
|
15
|
+
]);
|
|
5
16
|
|
|
6
17
|
const SESSION_ID_TOOLS = new Set([
|
|
7
18
|
'begin_task_context',
|
|
@@ -31,7 +42,8 @@ export function normalizeAgentSessionInput(
|
|
|
31
42
|
input,
|
|
32
43
|
nativeThreadId,
|
|
33
44
|
hostSessionId = nativeThreadId,
|
|
34
|
-
clock = () => new Date()
|
|
45
|
+
clock = () => new Date(),
|
|
46
|
+
sourceApplication = nativeThreadId ? 'codex' : 'other'
|
|
35
47
|
) {
|
|
36
48
|
if (name === WORKFLOW_OBSERVATION_TOOL) {
|
|
37
49
|
if (!hostSessionId) {
|
|
@@ -51,6 +63,24 @@ export function normalizeAgentSessionInput(
|
|
|
51
63
|
hostObservedAt: clock().toISOString()
|
|
52
64
|
};
|
|
53
65
|
}
|
|
66
|
+
if (PROJECT_AGENT_SOURCE_TOOLS.has(name)) {
|
|
67
|
+
if (!hostSessionId) {
|
|
68
|
+
throw new TypeError('Project Agent calls require an MCP host session');
|
|
69
|
+
}
|
|
70
|
+
const safeSourceApplication = normalizeMcpSourceApplication(sourceApplication);
|
|
71
|
+
const {
|
|
72
|
+
sourceApplication: _sourceApplication,
|
|
73
|
+
source_application: _source_application,
|
|
74
|
+
sourceSessionId: _sourceSessionId,
|
|
75
|
+
source_session_id: _source_session_id,
|
|
76
|
+
...safeInput
|
|
77
|
+
} = input ?? {};
|
|
78
|
+
return {
|
|
79
|
+
...safeInput,
|
|
80
|
+
sourceApplication: safeSourceApplication,
|
|
81
|
+
sourceSessionId: hostSessionId
|
|
82
|
+
};
|
|
83
|
+
}
|
|
54
84
|
if (!nativeThreadId || !SESSION_ID_TOOLS.has(name)) return input;
|
|
55
85
|
if (!input || typeof input !== 'object' || Array.isArray(input)) return input;
|
|
56
86
|
if (typeof input.sessionId !== 'string' || input.sessionId.trim() === nativeThreadId) {
|
|
@@ -58,3 +88,10 @@ export function normalizeAgentSessionInput(
|
|
|
58
88
|
}
|
|
59
89
|
return { ...input, sessionId: nativeThreadId };
|
|
60
90
|
}
|
|
91
|
+
|
|
92
|
+
export function normalizeMcpSourceApplication(value) {
|
|
93
|
+
if (!['codex', 'claude_code', 'cursor', 'kiro', 'other'].includes(value)) {
|
|
94
|
+
throw new TypeError('Unsupported MCP source application');
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
@@ -7,6 +7,19 @@ const READ_TOOLS = new Set([
|
|
|
7
7
|
'preview_common_knowledge_promotion',
|
|
8
8
|
'list_knowledge_spaces',
|
|
9
9
|
'list_personal_projects',
|
|
10
|
+
'list_project_agents',
|
|
11
|
+
'get_project_agent',
|
|
12
|
+
'list_project_agent_assignments',
|
|
13
|
+
'get_project_agent_context',
|
|
14
|
+
'view_project_agent_task',
|
|
15
|
+
'view_project_agent_activity',
|
|
16
|
+
'get_project_agent_recruitment_policy',
|
|
17
|
+
'list_project_agent_recruitments',
|
|
18
|
+
'list_executors',
|
|
19
|
+
'get_executor',
|
|
20
|
+
'list_executor_routing_rules',
|
|
21
|
+
'get_executor_routing_rule',
|
|
22
|
+
'list_project_agent_routing_learning',
|
|
10
23
|
'list_knowledge_review_candidates',
|
|
11
24
|
'list_workflow_candidates',
|
|
12
25
|
'recommend_next_workflow_steps',
|
|
@@ -36,6 +49,32 @@ const WRITE_TOOLS = new Set([
|
|
|
36
49
|
'search_human_knowledge_changes',
|
|
37
50
|
'review_human_knowledge_change',
|
|
38
51
|
'upsert_personal_project',
|
|
52
|
+
'upsert_project_agent',
|
|
53
|
+
'delete_project_agent',
|
|
54
|
+
'cleanup_test_project_agents',
|
|
55
|
+
'create_project_agent_assignment',
|
|
56
|
+
'end_project_agent_assignment',
|
|
57
|
+
'replace_project_agent_assignment',
|
|
58
|
+
'coordinate_project_agent_task',
|
|
59
|
+
'acquire_runtime_lease',
|
|
60
|
+
'refresh_runtime_lease',
|
|
61
|
+
'release_runtime_lease',
|
|
62
|
+
'submit_project_agent_task',
|
|
63
|
+
'record_project_agent_task_activity',
|
|
64
|
+
'update_project_agent_recruitment_policy',
|
|
65
|
+
'decide_project_agent_recruitment',
|
|
66
|
+
'upsert_executor',
|
|
67
|
+
'delete_executor',
|
|
68
|
+
'preflight_executor',
|
|
69
|
+
'authorize_executor',
|
|
70
|
+
'report_executor_health',
|
|
71
|
+
'upsert_executor_routing_rule',
|
|
72
|
+
'update_executor_routing_rule',
|
|
73
|
+
'delete_executor_routing_rule',
|
|
74
|
+
'record_project_agent_task_outcome',
|
|
75
|
+
'record_project_agent_executor_actual',
|
|
76
|
+
'ignore_project_agent_routing_learning',
|
|
77
|
+
'reset_project_agent_routing_learning',
|
|
39
78
|
'start_knowledge_review',
|
|
40
79
|
'record_knowledge_review_progress',
|
|
41
80
|
'finish_knowledge_review',
|
|
@@ -69,12 +108,42 @@ export function annotationsFor(name) {
|
|
|
69
108
|
readOnlyHint: readOnly,
|
|
70
109
|
destructiveHint: DESTRUCTIVE_TOOLS.has(name),
|
|
71
110
|
idempotentHint: readOnly || name === 'upsert_personal_project' ||
|
|
111
|
+
name === 'upsert_project_agent' ||
|
|
112
|
+
name === 'delete_project_agent' ||
|
|
113
|
+
name === 'cleanup_test_project_agents' ||
|
|
114
|
+
name === 'create_project_agent_assignment' ||
|
|
115
|
+
name === 'coordinate_project_agent_task' ||
|
|
116
|
+
name === 'refresh_runtime_lease' ||
|
|
117
|
+
name === 'release_runtime_lease' ||
|
|
118
|
+
name === 'submit_project_agent_task' ||
|
|
119
|
+
name === 'record_project_agent_task_activity' ||
|
|
120
|
+
name === 'record_project_agent_task_outcome' ||
|
|
121
|
+
name === 'record_project_agent_executor_actual' ||
|
|
122
|
+
name === 'upsert_executor' ||
|
|
123
|
+
name === 'preflight_executor' ||
|
|
124
|
+
name === 'authorize_executor' ||
|
|
125
|
+
name === 'report_executor_health' ||
|
|
126
|
+
name === 'upsert_executor_routing_rule' ||
|
|
127
|
+
name === 'update_executor_routing_rule' ||
|
|
72
128
|
name === 'publish_personal_project' || name === 'unsubscribe_public_project' ||
|
|
73
129
|
name === 'record_knowledge_usage' || name === 'record_decision_trace' ||
|
|
74
130
|
name === 'record_knowledge_feedback' ||
|
|
75
131
|
name === 'record_workflow_transition_observation' ||
|
|
76
132
|
name === 'checkpoint_task_knowledge',
|
|
77
133
|
openWorldHint: name === 'capture_session_knowledge' ||
|
|
134
|
+
name === 'coordinate_project_agent_task' ||
|
|
135
|
+
name === 'submit_project_agent_task' ||
|
|
136
|
+
name === 'record_project_agent_task_activity' ||
|
|
137
|
+
name === 'preflight_executor' ||
|
|
138
|
+
name === 'record_project_agent_task_outcome' ||
|
|
139
|
+
name === 'record_project_agent_executor_actual' ||
|
|
140
|
+
name === 'upsert_executor' ||
|
|
141
|
+
name === 'delete_executor' ||
|
|
142
|
+
name === 'authorize_executor' ||
|
|
143
|
+
name === 'report_executor_health' ||
|
|
144
|
+
name === 'upsert_executor_routing_rule' ||
|
|
145
|
+
name === 'update_executor_routing_rule' ||
|
|
146
|
+
name === 'delete_executor_routing_rule' ||
|
|
78
147
|
name === 'record_workflow_transition_observation' ||
|
|
79
148
|
name === 'search_connected_knowledge' ||
|
|
80
149
|
name === 'record_decision_trace' ||
|
package/src/mcp-server.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { callAgentTool, listAgentTools } from './agent-tools.js';
|
|
3
|
+
import {
|
|
4
|
+
bindRuntimeLeaseAgentTools,
|
|
5
|
+
createRuntimeLeaseClient
|
|
6
|
+
} from './adaptive-runtime/lease-client.js';
|
|
3
7
|
import { ApplicationError } from './app/application-error.js';
|
|
4
8
|
import { openFederatedGraphApplication } from './graphiti/federated-application.js';
|
|
5
9
|
import {
|
|
@@ -7,6 +11,7 @@ import {
|
|
|
7
11
|
resolveGraphRuntimeOptions
|
|
8
12
|
} from './graphiti/runtime-config.js';
|
|
9
13
|
import { runStdio } from './mcp/runtime.js';
|
|
14
|
+
import { normalizeMcpSourceApplication } from './mcp/session-id.js';
|
|
10
15
|
import { applicationErrorMessage } from './mcp/tool-result.js';
|
|
11
16
|
|
|
12
17
|
await main(process.argv.slice(2)).catch((error) => {
|
|
@@ -29,19 +34,30 @@ async function main(args) {
|
|
|
29
34
|
await runCall({ args, runtimeConfigPath });
|
|
30
35
|
return;
|
|
31
36
|
}
|
|
32
|
-
|
|
37
|
+
const configuredSourceApplication = args.includes('--source-application')
|
|
38
|
+
? requiredOption(args, '--source-application')
|
|
39
|
+
: null;
|
|
40
|
+
await runStdio({
|
|
41
|
+
runtimeConfigPath,
|
|
42
|
+
sourceApplication: configuredSourceApplication
|
|
43
|
+
? normalizeMcpSourceApplication(configuredSourceApplication)
|
|
44
|
+
: undefined
|
|
45
|
+
});
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
async function runCall({ args, runtimeConfigPath }) {
|
|
36
49
|
const app = openFederatedGraphApplication({ runtimeConfigPath });
|
|
50
|
+
const leaseClient = createRuntimeLeaseClient({ runtimeConfigPath });
|
|
51
|
+
bindRuntimeLeaseAgentTools(app, leaseClient);
|
|
37
52
|
try {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
parseInput(args)
|
|
53
|
+
const toolName = requiredOption(args, '--call');
|
|
54
|
+
const result = await leaseClient.withGraphLease(
|
|
55
|
+
`cli-call:${toolName}`,
|
|
56
|
+
() => callAgentTool(app, toolName, parseInput(args))
|
|
42
57
|
);
|
|
43
58
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
44
59
|
} finally {
|
|
60
|
+
await leaseClient.close();
|
|
45
61
|
await app.close();
|
|
46
62
|
}
|
|
47
63
|
}
|
|
@@ -69,7 +85,8 @@ function startupMessage(error) {
|
|
|
69
85
|
}
|
|
70
86
|
|
|
71
87
|
function helpText() {
|
|
72
|
-
return 'Usage: node src/mcp-server.js [--runtime-config <graph-runtime.json>]
|
|
88
|
+
return 'Usage: node src/mcp-server.js [--runtime-config <graph-runtime.json>] ' +
|
|
89
|
+
'[--source-application <codex|claude_code|cursor|kiro|other>]\n' +
|
|
73
90
|
' node src/mcp-server.js --tools\n' +
|
|
74
91
|
' node src/mcp-server.js --runtime-config <graph-runtime.json> ' +
|
|
75
92
|
'--call <tool> [--input <json>]\n';
|