fuli-context 0.7.6 → 0.7.8
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 +69 -13
- package/README.zh-CN.md +60 -14
- package/dist/web/assets/{AboutPage-sLV9WChi.js → AboutPage-9CVX91tr.js} +1 -1
- package/dist/web/assets/{ConnectionsPage-BWn4ywGJ.js → ConnectionsPage-CWbCVFdv.js} +1 -1
- package/dist/web/assets/EmployeeRecruitDialog-CQgNpGJ_.js +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-CfFlyKSh.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-CWg4WJhr.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-CwU4qBgD.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-B6TGAcFH.js +1 -0
- package/dist/web/assets/{KnowledgeEditDialog-DWUV_NPp.css → KnowledgeEditDialog-iv-dgUeD.css} +1 -1
- package/dist/web/assets/{KnowledgeInspector-CRQWOaos.js → KnowledgeInspector-M2pLY0bR.js} +1 -1
- package/dist/web/assets/{KnowledgeOrganizerPage-Dfj3vIpU.js → KnowledgeOrganizerPage-DzeAlk9b.js} +1 -1
- package/dist/web/assets/KnowledgePage-BJu9w0fF.js +1 -0
- package/dist/web/assets/{KnowledgeWorkspace-ChEB5Bwk.js → KnowledgeWorkspace-CCt8rnBb.js} +1 -1
- package/dist/web/assets/{OverviewPage-Cd66M0RT.js → OverviewPage-CZswVqui.js} +1 -1
- package/dist/web/assets/{PersonalProfilePage-RCFHL0Wz.js → PersonalProfilePage-f1nSF6kx.js} +1 -1
- package/dist/web/assets/PersonalProjectsPage-D__eJf0t.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-C3vW6wmk.css +1 -0
- package/dist/web/assets/ProjectAgentsPage-LrwagMGj.js +11 -0
- package/dist/web/assets/{PublicProjectsPage-mstPEjHe.js → PublicProjectsPage-BdC2Qk4n.js} +1 -1
- package/dist/web/assets/{ReviewPage-6Y1SmfZy.js → ReviewPage-Cbgl8_Si.js} +1 -1
- package/dist/web/assets/SearchableSelect-ERm-k4KI.js +1 -0
- package/dist/web/assets/{SettingsPage--LdTMUm7.js → SettingsPage-DWso4x29.js} +1 -1
- package/dist/web/assets/{WritingTastePage-CIpKswvs.js → WritingTastePage-CFpCjmIY.js} +1 -1
- package/dist/web/assets/catalog-WGLn7ERJ.js +1 -0
- package/dist/web/assets/{console-BT1P2Db4.js → console-DQgu0JIA.js} +1 -1
- package/dist/web/assets/conversation-launcher-settings-0KtlG_LV.js +1 -0
- package/dist/web/assets/{i18n-js6gfc7j.js → i18n-ByRiA3pJ.js} +3 -3
- package/dist/web/assets/{identity-CfDfanpa.js → identity-CxdPRMwH.js} +1 -1
- package/dist/web/assets/index-JAZe6lfX.js +2 -0
- package/dist/web/assets/index-wcXzzggp.css +1 -0
- package/dist/web/assets/{model-DJkLAJsg.js → model-Db4-KefQ.js} +1 -1
- package/dist/web/assets/{useApi-CROJJdhE-BdSti7Y2.js → useApi-CROJJdhE-CePMjc08.js} +1 -1
- package/dist/web/assets/{vue-router-Kk67EaCP.js → vue-router-CzX-hn3P.js} +1 -1
- package/dist/web/index.html +7 -6
- package/docs/employee-agents.md +99 -0
- package/docs/project-agent-memory.md +479 -0
- package/graph-provider/fuli_graph/knowledge_audit_models.py +171 -0
- package/graph-provider/fuli_graph/model_base.py +5 -0
- package/graph-provider/fuli_graph/model_validation.py +32 -0
- package/graph-provider/fuli_graph/models.py +26 -170
- package/graph-provider/fuli_graph/project_agent_context_models.py +29 -0
- package/graph-provider/fuli_graph/project_agent_executor_models.py +35 -7
- package/graph-provider/fuli_graph/project_agent_memory_models.py +79 -0
- package/graph-provider/fuli_graph/project_agent_memory_routes.py +46 -0
- package/graph-provider/fuli_graph/project_agent_models.py +9 -0
- package/graph-provider/fuli_graph/project_agent_recruitment_values.py +48 -0
- package/graph-provider/fuli_graph/project_agent_routes.py +21 -1
- package/graph-provider/fuli_graph/project_agent_task_models.py +217 -29
- package/graph-provider/fuli_graph/runtime.py +37 -1
- package/graph-provider/fuli_graph/store.py +6 -0
- package/graph-provider/fuli_graph/store_project_agent_context.py +65 -0
- package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +175 -11
- package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +33 -10
- package/graph-provider/fuli_graph/store_project_agent_executors.py +181 -14
- package/graph-provider/fuli_graph/store_project_agent_memory.py +174 -0
- package/graph-provider/fuli_graph/store_project_agent_task_activity.py +423 -0
- package/graph-provider/fuli_graph/store_project_agent_task_persistence.py +152 -0
- package/graph-provider/fuli_graph/store_project_agent_task_reads.py +187 -21
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +748 -162
- package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +230 -18
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +261 -468
- package/graph-provider/fuli_graph/store_project_agents.py +214 -46
- package/graph-provider/fuli_graph/store_task_contexts.py +217 -0
- package/graph-provider/fuli_graph/store_transactions.py +40 -0
- package/graph-provider/fuli_graph/task_context_models.py +50 -0
- package/graph-provider/fuli_graph/task_context_routes.py +31 -0
- package/graph-provider/fuli_graph/workflow_observation_models.py +1 -1
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +8 -8
- package/package.json +5 -2
- package/skills/capturing-session-knowledge/SKILL.md +18 -6
- package/src/adaptive-runtime/executor-pool.js +46 -5
- package/src/adaptive-runtime/graph-services.js +10 -3
- package/src/adaptive-runtime/lease-client.js +66 -14
- package/src/adaptive-runtime/runtime-broker.js +24 -9
- package/src/agent-tools/employee-definitions.js +43 -0
- package/src/agent-tools/graph-definitions.js +25 -6
- package/src/agent-tools/graph-handlers.js +11 -0
- package/src/agent-tools/project-agent-definitions.js +35 -4
- package/src/agent-tools/project-agent-memory-definitions.js +36 -0
- package/src/agent-tools.js +6 -2
- package/src/agents/codex/lifecycle-hook.js +107 -0
- package/src/agents/codex/lifecycle-hooks.js +231 -0
- package/src/agents/cursor/lifecycle-hook.js +133 -0
- package/src/agents/cursor/lifecycle-hooks.js +50 -0
- package/src/agents/lifecycle-message.js +19 -0
- package/src/app/agent-request-context.js +23 -0
- package/src/cli/command-registry.js +2 -0
- package/src/cli/employee-command.js +17 -0
- package/src/cli/remote-mcp-command.js +282 -0
- package/src/cli/setup-command.js +5 -0
- package/src/cli/update-command.js +6 -43
- package/src/cli.js +10 -0
- package/src/employees/catalog/jefa.json +21 -0
- package/src/employees/install-package.js +77 -0
- package/src/employees/management-policy.js +88 -0
- package/src/employees/manifest.js +53 -0
- package/src/employees/package-registry.js +107 -0
- package/src/employees/project-selection.js +50 -0
- package/src/employees/recruitment.js +199 -0
- package/src/employees/service.js +83 -0
- package/src/employees/task-entry.js +39 -0
- package/src/graphiti/agent-knowledge-workflows.js +135 -25
- package/src/graphiti/federated-application.js +78 -35
- package/src/graphiti/project-agent-control-plane.js +20 -3
- package/src/graphiti/project-agent-mapping.js +155 -5
- package/src/graphiti/project-agent-memory.js +115 -0
- package/src/graphiti/project-agent-task-entry.js +126 -0
- package/src/graphiti/project-agent-workflows.js +30 -14
- package/src/graphiti/provider-client.js +66 -4
- package/src/http/api-router.js +30 -5
- package/src/http/employee-api-router.js +64 -0
- package/src/http/error-mapping.js +4 -0
- package/src/http/graph-api-router.js +2 -0
- package/src/http/request-policy.js +6 -3
- package/src/http/static-handler.js +4 -3
- package/src/mcp/create-mcp-server.js +98 -37
- package/src/mcp/direct-call.js +38 -0
- package/src/mcp/instructions.js +8 -7
- package/src/mcp/provider-task-context-registry.js +74 -0
- package/src/mcp/remote-http-server.js +761 -0
- package/src/mcp/session-id.js +29 -3
- package/src/mcp/task-context-registry.js +88 -29
- package/src/mcp/tool-annotations.js +10 -2
- package/src/mcp/tool-result.js +8 -3
- package/src/mcp-server.js +20 -8
- package/src/native-runtime/runtime.js +58 -8
- package/src/semantic-version.js +42 -0
- package/src/server.js +76 -28
- package/src/setup/agent-installation-status.js +38 -6
- package/src/setup/agents.js +20 -8
- package/src/setup/claude-code-config.js +55 -13
- package/src/setup/codex-bootstrap.js +11 -10
- package/src/setup/codex-config.js +74 -7
- package/src/setup/config-backup.js +18 -2
- package/src/setup/cursor-config.js +22 -5
- package/src/setup/setup.js +30 -22
- package/src/storage/json-file.js +11 -3
- package/src/system/package-version-checker.js +72 -0
- package/src/system/system-service.js +3 -0
- package/dist/web/assets/KnowledgeEditDialog-CZ5ziPrD.js +0 -1
- package/dist/web/assets/KnowledgePage-BRYC9S5Y.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-DEh8XWby.js +0 -1
- package/dist/web/assets/ProjectAgentsPage-Crh7PrXa.css +0 -1
- package/dist/web/assets/ProjectAgentsPage-DPnaH-TR.js +0 -11
- package/dist/web/assets/SearchableSelect-D3HM8YF8.js +0 -1
- package/dist/web/assets/conversation-launcher-settings-DrJEotdf.js +0 -1
- package/dist/web/assets/index-BnH5mcZx.css +0 -1
- package/dist/web/assets/index-GqJf1xqg.js +0 -2
|
@@ -14,13 +14,15 @@ export function createRuntimeLeaseClient({
|
|
|
14
14
|
clearHeartbeat = clearInterval
|
|
15
15
|
}) {
|
|
16
16
|
const leases = new Map();
|
|
17
|
+
const acquisitions = new Set();
|
|
18
|
+
let closed = false;
|
|
17
19
|
|
|
18
|
-
async function withGraphLease(owner, operation) {
|
|
19
|
-
return withLease({ kind: 'graph', owner }, operation);
|
|
20
|
+
async function withGraphLease(owner, operation, requestContext = null) {
|
|
21
|
+
return withLease({ kind: 'graph', owner }, operation, requestContext);
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
async function withExecutorLease(executorId, owner, operation) {
|
|
23
|
-
return withLease({ kind: 'executor', executorId, owner }, operation);
|
|
24
|
+
async function withExecutorLease(executorId, owner, operation, requestContext = null) {
|
|
25
|
+
return withLease({ kind: 'executor', executorId, owner }, operation, requestContext);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
async function acquireGraphLease(owner) {
|
|
@@ -31,7 +33,19 @@ export function createRuntimeLeaseClient({
|
|
|
31
33
|
return acquireLease({ kind: 'executor', executorId, owner });
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
async function acquireLease(input) {
|
|
36
|
+
async function acquireLease(input, signal = null) {
|
|
37
|
+
assertOpen();
|
|
38
|
+
signal?.throwIfAborted();
|
|
39
|
+
const acquisition = acquireOpenLease(input, signal);
|
|
40
|
+
acquisitions.add(acquisition);
|
|
41
|
+
try {
|
|
42
|
+
return await acquisition;
|
|
43
|
+
} finally {
|
|
44
|
+
acquisitions.delete(acquisition);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function acquireOpenLease(input, signal = null) {
|
|
35
49
|
const settings = readSettings(paths.adaptiveRuntimeSettingsPath);
|
|
36
50
|
if (!settings.enabled) return disabledLease();
|
|
37
51
|
|
|
@@ -40,10 +54,24 @@ export function createRuntimeLeaseClient({
|
|
|
40
54
|
method: 'POST',
|
|
41
55
|
body: input,
|
|
42
56
|
timeoutMs: 180_000,
|
|
43
|
-
fetchImpl
|
|
57
|
+
fetchImpl,
|
|
58
|
+
signal
|
|
44
59
|
});
|
|
45
60
|
const handle = publicLease(lease);
|
|
46
|
-
if (!handle.enabled)
|
|
61
|
+
if (!handle.enabled) {
|
|
62
|
+
const explicitlyDisabled = lease?.enabled === false && lease.leaseId === null;
|
|
63
|
+
if (!explicitlyDisabled) {
|
|
64
|
+
// Preserve a usable ID before rejecting a malformed success response.
|
|
65
|
+
// Without one, remote TTL is the only available cleanup mechanism.
|
|
66
|
+
if (typeof lease?.leaseId === 'string' && lease.leaseId.trim()) {
|
|
67
|
+
await releaseRemote({ consoleUrl, handle: { leaseId: lease.leaseId } }).catch(() => {});
|
|
68
|
+
}
|
|
69
|
+
throw new Error('Invalid runtime lease response');
|
|
70
|
+
}
|
|
71
|
+
assertOpen();
|
|
72
|
+
signal?.throwIfAborted();
|
|
73
|
+
return handle;
|
|
74
|
+
}
|
|
47
75
|
|
|
48
76
|
const entry = {
|
|
49
77
|
handle,
|
|
@@ -55,6 +83,8 @@ export function createRuntimeLeaseClient({
|
|
|
55
83
|
};
|
|
56
84
|
leases.set(handle.leaseId, entry);
|
|
57
85
|
try {
|
|
86
|
+
assertOpen();
|
|
87
|
+
signal?.throwIfAborted();
|
|
58
88
|
startHeartbeat(entry, settings);
|
|
59
89
|
return { ...entry.handle };
|
|
60
90
|
} catch (error) {
|
|
@@ -89,10 +119,13 @@ export function createRuntimeLeaseClient({
|
|
|
89
119
|
}
|
|
90
120
|
}
|
|
91
121
|
|
|
92
|
-
async function withLease(input, operation) {
|
|
122
|
+
async function withLease(input, operation, requestContext = null) {
|
|
93
123
|
if (typeof operation !== 'function') throw new TypeError('Runtime operation is required');
|
|
94
|
-
const
|
|
124
|
+
const signal = agentRequestSignal(requestContext);
|
|
125
|
+
signal?.throwIfAborted();
|
|
126
|
+
const handle = await acquireLease(input, signal);
|
|
95
127
|
try {
|
|
128
|
+
signal?.throwIfAborted();
|
|
96
129
|
return await operation();
|
|
97
130
|
} finally {
|
|
98
131
|
await releaseLease(handle);
|
|
@@ -100,8 +133,16 @@ export function createRuntimeLeaseClient({
|
|
|
100
133
|
}
|
|
101
134
|
|
|
102
135
|
async function close() {
|
|
136
|
+
closed = true;
|
|
103
137
|
const handles = [...leases.values()].map(({ handle }) => ({ ...handle }));
|
|
104
|
-
await Promise.allSettled(
|
|
138
|
+
await Promise.allSettled([
|
|
139
|
+
...acquisitions,
|
|
140
|
+
...handles.map((handle) => releaseLease(handle))
|
|
141
|
+
]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function assertOpen() {
|
|
145
|
+
if (closed) throw new Error('Runtime lease client is closed');
|
|
105
146
|
}
|
|
106
147
|
|
|
107
148
|
function startHeartbeat(entry, settings) {
|
|
@@ -184,7 +225,8 @@ export function createRuntimeLeaseClient({
|
|
|
184
225
|
}
|
|
185
226
|
return { ...entry.handle, refreshed };
|
|
186
227
|
} catch (error) {
|
|
187
|
-
|
|
228
|
+
// A transient request failure must not abandon a still-running operation.
|
|
229
|
+
// The next heartbeat retries; release/close or refreshed:false stops it.
|
|
188
230
|
throw error;
|
|
189
231
|
}
|
|
190
232
|
})();
|
|
@@ -269,7 +311,7 @@ function publicLease(value, fallback = null) {
|
|
|
269
311
|
...(fallback && typeof fallback === 'object' ? fallback : {}),
|
|
270
312
|
...(value && typeof value === 'object' ? value : {})
|
|
271
313
|
};
|
|
272
|
-
if (source.enabled !== true || typeof source.leaseId !== 'string' || !source.leaseId) {
|
|
314
|
+
if (source.enabled !== true || typeof source.leaseId !== 'string' || !source.leaseId.trim()) {
|
|
273
315
|
return disabledLease();
|
|
274
316
|
}
|
|
275
317
|
const handle = {
|
|
@@ -311,13 +353,15 @@ async function requestJson(url, {
|
|
|
311
353
|
method,
|
|
312
354
|
body,
|
|
313
355
|
timeoutMs,
|
|
314
|
-
fetchImpl
|
|
356
|
+
fetchImpl,
|
|
357
|
+
signal = null
|
|
315
358
|
}) {
|
|
359
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
316
360
|
const response = await fetchImpl(url, {
|
|
317
361
|
method,
|
|
318
362
|
headers: body === undefined ? undefined : { 'content-type': 'application/json' },
|
|
319
363
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
320
|
-
signal: AbortSignal.
|
|
364
|
+
signal: signal ? AbortSignal.any([timeoutSignal, signal]) : timeoutSignal
|
|
321
365
|
});
|
|
322
366
|
if (!response.ok) {
|
|
323
367
|
let detail = null;
|
|
@@ -333,3 +377,11 @@ async function requestJson(url, {
|
|
|
333
377
|
}
|
|
334
378
|
return response.json();
|
|
335
379
|
}
|
|
380
|
+
|
|
381
|
+
function agentRequestSignal(value) {
|
|
382
|
+
const signal = value?.signal;
|
|
383
|
+
return signal && typeof signal.addEventListener === 'function' &&
|
|
384
|
+
typeof signal.throwIfAborted === 'function'
|
|
385
|
+
? signal
|
|
386
|
+
: null;
|
|
387
|
+
}
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
writeAdaptiveRuntimeState
|
|
10
10
|
} from './state.js';
|
|
11
11
|
|
|
12
|
+
const IDLE_FAILURE_RETRY_MS = 30_000;
|
|
13
|
+
|
|
12
14
|
export function createAdaptiveRuntimeBroker({
|
|
13
15
|
paths,
|
|
14
16
|
settings,
|
|
@@ -33,12 +35,14 @@ export function createAdaptiveRuntimeBroker({
|
|
|
33
35
|
let databaseTimer = null;
|
|
34
36
|
let transition = Promise.resolve();
|
|
35
37
|
let closed = false;
|
|
38
|
+
let closePromise = null;
|
|
39
|
+
let idleRetryAt = 0;
|
|
36
40
|
|
|
37
41
|
scheduleIdle();
|
|
38
42
|
|
|
39
43
|
async function acquire(input = {}) {
|
|
40
44
|
if (!configured.enabled) return disabledLease();
|
|
41
|
-
|
|
45
|
+
assertOpen();
|
|
42
46
|
const kind = input.kind ?? 'graph';
|
|
43
47
|
if (!['graph', 'executor'].includes(kind)) {
|
|
44
48
|
throw new TypeError('Runtime lease kind must be graph or executor');
|
|
@@ -56,18 +60,22 @@ export function createAdaptiveRuntimeBroker({
|
|
|
56
60
|
};
|
|
57
61
|
leases.set(leaseId, lease);
|
|
58
62
|
clearIdleTimers();
|
|
59
|
-
armExpiry(lease);
|
|
60
63
|
try {
|
|
61
64
|
await exclusive(async () => {
|
|
65
|
+
assertOpen();
|
|
62
66
|
await ensureAwake();
|
|
63
67
|
if (executorId) await executorPool.acquire(executorId, leaseId);
|
|
64
68
|
});
|
|
69
|
+
assertOpen();
|
|
70
|
+
idleRetryAt = 0;
|
|
71
|
+
// The caller can only heartbeat after startup returns its lease handle.
|
|
72
|
+
armExpiry(lease);
|
|
65
73
|
return publicLease(lease);
|
|
66
74
|
} catch (error) {
|
|
67
75
|
leases.delete(leaseId);
|
|
68
76
|
if (lease.timer) clearTimer(lease.timer);
|
|
69
77
|
if (executorId) executorPool.release(executorId, leaseId);
|
|
70
|
-
touch();
|
|
78
|
+
touch(errorMessage(error));
|
|
71
79
|
scheduleIdle();
|
|
72
80
|
throw error;
|
|
73
81
|
}
|
|
@@ -126,14 +134,19 @@ export function createAdaptiveRuntimeBroker({
|
|
|
126
134
|
}
|
|
127
135
|
|
|
128
136
|
function close() {
|
|
129
|
-
if (closed) return;
|
|
137
|
+
if (closed) return closePromise;
|
|
130
138
|
closed = true;
|
|
131
139
|
clearIdleTimers();
|
|
132
140
|
for (const lease of leases.values()) {
|
|
133
141
|
if (lease.timer) clearTimer(lease.timer);
|
|
134
142
|
}
|
|
135
143
|
leases.clear();
|
|
136
|
-
executorPool.close();
|
|
144
|
+
closePromise = executorPool.close();
|
|
145
|
+
return closePromise;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function assertOpen() {
|
|
149
|
+
if (closed) throw new Error('Adaptive runtime coordinator is closed');
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
async function ensureAwake() {
|
|
@@ -175,9 +188,11 @@ export function createAdaptiveRuntimeBroker({
|
|
|
175
188
|
await operation();
|
|
176
189
|
}).catch((error) => {
|
|
177
190
|
persist('degraded', errorMessage(error));
|
|
191
|
+
// A missed idle deadline must not become a zero-delay failure loop.
|
|
192
|
+
idleRetryAt = now() + IDLE_FAILURE_RETRY_MS;
|
|
178
193
|
scheduleIdle();
|
|
179
194
|
});
|
|
180
|
-
}, Math.max(0, timestamp - now()));
|
|
195
|
+
}, Math.max(0, timestamp - now(), idleRetryAt - now()));
|
|
181
196
|
timer?.unref?.();
|
|
182
197
|
return timer;
|
|
183
198
|
}
|
|
@@ -241,8 +256,8 @@ export function createAdaptiveRuntimeBroker({
|
|
|
241
256
|
return initial;
|
|
242
257
|
}
|
|
243
258
|
|
|
244
|
-
function touch() {
|
|
245
|
-
state = persistValue({ ...state, lastActivityAt: isoNow(), lastError
|
|
259
|
+
function touch(lastError = null) {
|
|
260
|
+
state = persistValue({ ...state, lastActivityAt: isoNow(), lastError });
|
|
246
261
|
}
|
|
247
262
|
|
|
248
263
|
function persist(stage, lastError = null) {
|
|
@@ -260,7 +275,7 @@ export function createAdaptiveRuntimeBroker({
|
|
|
260
275
|
|
|
261
276
|
function nextSleepAt(lastActivityMs, idleSeconds, stages) {
|
|
262
277
|
if (!configured.enabled || leases.size > 0 || !stages.includes(state.stage)) return null;
|
|
263
|
-
return new Date(lastActivityMs + idleSeconds * 1000).toISOString();
|
|
278
|
+
return new Date(Math.max(lastActivityMs + idleSeconds * 1000, idleRetryAt)).toISOString();
|
|
264
279
|
}
|
|
265
280
|
|
|
266
281
|
function clearIdleTimers() {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { booleanSchema, objectSchema, stringSchema } from './schema.js';
|
|
2
|
+
|
|
3
|
+
const id = { ...stringSchema(), minLength: 1, maxLength: 256 };
|
|
4
|
+
const projectPath = { ...stringSchema(), minLength: 1, maxLength: 4096 };
|
|
5
|
+
const target = { projectPath, templateId: id };
|
|
6
|
+
|
|
7
|
+
export const EMPLOYEE_TOOL_DEFINITIONS = [
|
|
8
|
+
{
|
|
9
|
+
name: 'list_employee_templates', title: 'READ · Employee catalog',
|
|
10
|
+
description: 'List reusable employee Agent templates, recruitment state, assignments and installed workbench availability. This does not recruit or start an executor.',
|
|
11
|
+
inputSchema: objectSchema({})
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'recruit_employee', title: 'WRITE · Recruit an employee',
|
|
15
|
+
description: 'On an explicit user request recruit an employee. New recruitment without a scope uses the template default (Jefa: all projects, including future projects). Existing identities retain their saved scope. Use management.mode=all plus excludedProjectIds for a persistent all-except rule, or mode=selected plus projectIds for a fixed selection. Never combine management with projectPath/personalProjectIds. Changing existing management requires replaceAssignments and expectedAssignmentsVersion from the catalog. Legacy projectPath or personalProjectIds remains a current-project selection. Exclusions take effect before assignment synchronization; data and history are preserved. Reload after conflicts or incomplete updates. No models or workers start. Reactivation must be explicitly requested.',
|
|
16
|
+
inputSchema: objectSchema({
|
|
17
|
+
...target, reactivate: booleanSchema(),
|
|
18
|
+
personalProjectIds: { type: 'array', items: id, maxItems: 500 },
|
|
19
|
+
replaceAssignments: booleanSchema(),
|
|
20
|
+
expectedAssignmentsVersion: { ...stringSchema(), minLength: 1, maxLength: 128 },
|
|
21
|
+
management: objectSchema({
|
|
22
|
+
mode: { type: 'string', enum: ['all', 'selected'] },
|
|
23
|
+
projectIds: { type: 'array', items: id, maxItems: 500 },
|
|
24
|
+
excludedProjectIds: { type: 'array', items: id, maxItems: 500 },
|
|
25
|
+
titleMode: { type: 'string', enum: ['off', 'suggest', 'auto'] },
|
|
26
|
+
titleStyle: { type: 'string', enum: ['text', 'emoji'] },
|
|
27
|
+
}, ['mode']),
|
|
28
|
+
}, ['templateId'])
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'list_employee_tools', title: 'READ · Employee workbench tools',
|
|
32
|
+
description: 'Discover the exact input schemas and permissions for a recruited employee in the current project. Read these schemas before calling a tool; a workbench has to be installed first.',
|
|
33
|
+
inputSchema: objectSchema(target, ['projectPath', 'templateId'])
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'call_employee_tool', title: 'WRITE · Call an employee workbench tool',
|
|
37
|
+
description: 'Call a discovered employee tool inside the exact assigned project. May read or change data according to the tool schema. Preserve optimistic concurrency and idempotency keys. Does not grant cross-project access, execute an external model, or confirm task completion for the human.',
|
|
38
|
+
inputSchema: objectSchema({
|
|
39
|
+
...target, tool: id,
|
|
40
|
+
arguments: { type: 'object', additionalProperties: true }
|
|
41
|
+
}, ['projectPath', 'templateId', 'tool', 'arguments'])
|
|
42
|
+
}
|
|
43
|
+
];
|
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
recruitmentStatus,
|
|
32
32
|
routingRuleScope
|
|
33
33
|
} from './project-agent-definitions.js';
|
|
34
|
+
import { PROJECT_AGENT_MEMORY_DEFINITIONS, workingMemorySchema } from './project-agent-memory-definitions.js';
|
|
35
|
+
import { EMPLOYEE_TOOL_DEFINITIONS } from './employee-definitions.js';
|
|
34
36
|
|
|
35
37
|
const id = boundedString(256);
|
|
36
38
|
const label = boundedString(512);
|
|
@@ -98,7 +100,7 @@ const profileAspect = {
|
|
|
98
100
|
};
|
|
99
101
|
const sourceApplication = {
|
|
100
102
|
type: ['string', 'null'],
|
|
101
|
-
enum: ['codex', 'claude_code', 'cursor', 'kiro', 'other', null]
|
|
103
|
+
enum: ['codex', 'claude', 'claude_code', 'cursor', 'kiro', 'other', null]
|
|
102
104
|
};
|
|
103
105
|
const epistemicFields = {
|
|
104
106
|
originQuadrant: epistemicQuadrant,
|
|
@@ -276,13 +278,19 @@ const workflowObservedStep = objectSchema({
|
|
|
276
278
|
}, ['actionId', 'name']);
|
|
277
279
|
|
|
278
280
|
export const GRAPH_TOOL_DEFINITIONS = [
|
|
281
|
+
...EMPLOYEE_TOOL_DEFINITIONS,
|
|
279
282
|
{
|
|
280
283
|
name: 'begin_task_context',
|
|
281
284
|
title: 'LIFECYCLE · Begin a Fuli-aware task',
|
|
282
|
-
description: 'Lifecycle entry used by supported Agent hooks before the model processes a user prompt. It resolves the exact local project from projectPath, loads effective collaboration preferences, and uses taskPrompt transiently for bounded automatic recall when the request signals a stable prior fact, runbook, URL, decision, release, deployment, or authentication method. It never stores or returns projectPath or taskPrompt. Inspect task_knowledge_recall before asking the user to repeat stable context. Returns an opaque taskContextToken. Claude Code
|
|
285
|
+
description: 'Lifecycle entry used by supported Agent hooks before the model processes a user prompt. It resolves the exact local project from projectPath, loads effective collaboration preferences, and uses taskPrompt transiently for bounded automatic recall when the request signals a stable prior fact, runbook, URL, decision, release, deployment, or authentication method. It never stores or returns projectPath or taskPrompt. Inspect task_knowledge_recall before asking the user to repeat stable context. Returns an opaque taskContextToken. Fuli setup generates Claude Code and Codex UserPromptSubmit hook configuration and a Cursor task-entry adapter. Configuration is not proof of host loading, trust, or execution. Use supplied hook context without repeating the preference fallback; Cursor retrieves context through the Agent when its hook cannot inject it.',
|
|
283
286
|
inputSchema: objectSchema({
|
|
284
287
|
sessionId: id,
|
|
288
|
+
turnId: id,
|
|
285
289
|
projectPath: boundedString(4096),
|
|
290
|
+
personalProjectId: nullableStringSchema(),
|
|
291
|
+
projectAgentId: nullableStringSchema(),
|
|
292
|
+
workKind: boundedString(128),
|
|
293
|
+
requiredCapabilities: arraySchema(boundedString(512), { maxItems: 16 }),
|
|
286
294
|
taskPrompt: boundedString(8192)
|
|
287
295
|
}, ['sessionId', 'projectPath'])
|
|
288
296
|
},
|
|
@@ -294,7 +302,11 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
294
302
|
taskContextToken: id,
|
|
295
303
|
disposition: enumSchema(['capture_candidates', 'retain_nothing']),
|
|
296
304
|
reason: boundedString(2000),
|
|
297
|
-
capture: objectSchema(captureEpisodeFields, captureEpisodeRequired)
|
|
305
|
+
capture: objectSchema(captureEpisodeFields, captureEpisodeRequired),
|
|
306
|
+
agentMemory: objectSchema({
|
|
307
|
+
expectedRevision: integerSchema({ minimum: 0 }),
|
|
308
|
+
memory: workingMemorySchema
|
|
309
|
+
}, ['expectedRevision', 'memory'])
|
|
298
310
|
}, ['taskContextToken', 'disposition', 'reason'])
|
|
299
311
|
},
|
|
300
312
|
{
|
|
@@ -308,10 +320,13 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
308
320
|
title: 'READ FIRST · Load task collaboration preferences',
|
|
309
321
|
description: 'Fallback for Agents or tasks without begin_task_context hook context. When no hook context was supplied, call this exact tool name at the start of every user task before any other tool or answer; never substitute a project action tool. Do not call it redundantly when the entry hook already supplied preferences. Pass projectPath as the current working directory and taskPrompt as the current user request. Fuli uses both transiently, never stores or returns them, resolves one exact registered local project, and performs bounded automatic recall only when the request signals stable prior context. Inspect task_knowledge_recall before asking the user to repeat a project fact or method. On a miss, search_current_project_knowledge with one to four focused action, artifact, target-system, or identifier queries; never use the full conversational request as the only query. Apply effective_preferences before answering or constructing tool arguments. Resolve only relevant deferred_conflicts first. For write tools, enforce preferences in the actual payload; the final answer is not compliance. Personal-global preferences always apply; conflicted, pending, invalid, ambiguous-project, and unrelated-project items never auto-apply. Automatic injection does not count as usage evidence. personalProjectId remains an explicit compatibility override.',
|
|
310
322
|
inputSchema: objectSchema({
|
|
323
|
+
sessionId: id,
|
|
311
324
|
projectPath: boundedString(4096),
|
|
312
325
|
taskPrompt: boundedString(8192),
|
|
313
326
|
personalProjectId: nullableStringSchema(),
|
|
314
327
|
projectAgentId: nullableStringSchema(),
|
|
328
|
+
workKind: boundedString(128),
|
|
329
|
+
requiredCapabilities: arraySchema(boundedString(512), { maxItems: 16 }),
|
|
315
330
|
limit: integerSchema({ minimum: 1, maximum: 200 })
|
|
316
331
|
}, ['projectPath'])
|
|
317
332
|
},
|
|
@@ -514,6 +529,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
514
529
|
description: 'High-level project search for normal Agent work. Pass projectPath plus one or more focused queries; Fuli resolves the exact local project, searches its local knowledge first, then follows outgoing PART_OF or USES_KNOWLEDGE_FROM relations to authorized parent/source knowledge. An exact current-project item with the same stable key overrides an inherited item. The tool never guesses an ambiguous project and never traverses RELATED_TO. Instead it returns structured related_project_suggestions so the Agent can ask whether to add exactly one related project to this read-only search; explicit human confirmation is required before any expansion.',
|
|
515
530
|
inputSchema: objectSchema({
|
|
516
531
|
projectPath: boundedString(4096),
|
|
532
|
+
personalProjectId: nullableStringSchema(),
|
|
517
533
|
queries: arraySchema(shortText, { minItems: 1, maxItems: 10 }),
|
|
518
534
|
limitPerQuery: integerSchema({ minimum: 1, maximum: 50 }),
|
|
519
535
|
includeHistorical: booleanSchema(),
|
|
@@ -671,6 +687,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
671
687
|
agentId: id
|
|
672
688
|
}, ['personalSpaceId', 'agentId'])
|
|
673
689
|
},
|
|
690
|
+
...PROJECT_AGENT_MEMORY_DEFINITIONS,
|
|
674
691
|
{
|
|
675
692
|
name: 'delete_project_agent',
|
|
676
693
|
title: 'WRITE · Archive one Agent identity',
|
|
@@ -759,6 +776,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
759
776
|
description: 'View one task with lead/collaborator assignments, routing decision, effective model strategy, source client/session, event history, actual executor/model, routing rule, and fallback audit. Missing connected state is not synthesized.',
|
|
760
777
|
inputSchema: objectSchema({
|
|
761
778
|
personalSpaceId: id,
|
|
779
|
+
personalProjectId: id,
|
|
762
780
|
taskId: id,
|
|
763
781
|
includeEvents: booleanSchema()
|
|
764
782
|
}, ['personalSpaceId', 'taskId'])
|
|
@@ -766,7 +784,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
766
784
|
{
|
|
767
785
|
name: 'record_project_agent_task_activity',
|
|
768
786
|
title: 'WRITE · Record task activity',
|
|
769
|
-
description: 'Record one explicit task event, including real terminal activity
|
|
787
|
+
description: 'Record one explicit task event, including real terminal activity, actual executor/model/client attribution, and an optional source-labelled cumulative token snapshot for the concrete worker. Never estimate missing usage. Terminal activity is the only source for per-Agent activity summaries.',
|
|
770
788
|
inputSchema: projectAgentTaskActivityInput
|
|
771
789
|
},
|
|
772
790
|
{
|
|
@@ -775,6 +793,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
775
793
|
description: 'Return actual per-Agent daily completed/failed/cancelled activity and verifiable summaries. No history is fabricated and configured Agent status is not treated as running state.',
|
|
776
794
|
inputSchema: objectSchema({
|
|
777
795
|
personalSpaceId: id,
|
|
796
|
+
personalProjectId: id,
|
|
778
797
|
agentId: id,
|
|
779
798
|
fromDate: nullableStringSchema(),
|
|
780
799
|
toDate: nullableStringSchema()
|
|
@@ -806,13 +825,13 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
806
825
|
{
|
|
807
826
|
name: 'get_project_agent_recruitment_policy',
|
|
808
827
|
title: 'READ · Get recruitment policy',
|
|
809
|
-
description: '
|
|
828
|
+
description: 'Deprecated: read the legacy stored space setting, which does not control recruitment. Use get_project_agent_coordination_policy for the effective exact-project switches.',
|
|
810
829
|
inputSchema: objectSchema({ personalSpaceId: id }, ['personalSpaceId'])
|
|
811
830
|
},
|
|
812
831
|
{
|
|
813
832
|
name: 'update_project_agent_recruitment_policy',
|
|
814
833
|
title: 'WRITE · Set recruitment policy',
|
|
815
|
-
description: '
|
|
834
|
+
description: 'Deprecated compatibility storage only; this does not change recruitment authorization. Use update_project_agent_coordination_policy with the exact project and askBeforeRecruitment instead. The response warns that this legacy value is not effective.',
|
|
816
835
|
inputSchema: objectSchema({
|
|
817
836
|
personalSpaceId: id,
|
|
818
837
|
confirmationMode: recruitmentConfirmationMode
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ApplicationError } from '../app/application-error.js';
|
|
2
2
|
|
|
3
3
|
const HANDLERS = Object.freeze({
|
|
4
|
+
list_employee_templates: (app, input) => employeeService(app).list(input),
|
|
5
|
+
recruit_employee: (app, input) => employeeService(app).recruit(input),
|
|
6
|
+
list_employee_tools: (app, input) => employeeService(app).describeTools(input),
|
|
7
|
+
call_employee_tool: (app, input) => employeeService(app).callTool(input),
|
|
4
8
|
begin_task_context: (app, input) => app.beginTaskContext(input),
|
|
5
9
|
checkpoint_task_knowledge: (app, input) =>
|
|
6
10
|
app.checkpointTaskKnowledge(input),
|
|
@@ -82,6 +86,8 @@ const HANDLERS = Object.freeze({
|
|
|
82
86
|
replace_project_agent_assignment: (app, input) =>
|
|
83
87
|
app.replaceProjectAgentAssignment(input),
|
|
84
88
|
get_project_agent_context: (app, input) => app.getProjectAgentContext(input),
|
|
89
|
+
get_project_agent_memory: (app, input) => app.getProjectAgentMemory(input),
|
|
90
|
+
checkpoint_project_agent_memory: (app, input) => app.checkpointProjectAgentMemory(input),
|
|
85
91
|
coordinate_project_agent_task: (app, input) =>
|
|
86
92
|
app.coordinateProjectAgentTask(input),
|
|
87
93
|
acquire_runtime_lease: (app, input) => app.acquireRuntimeLease(input),
|
|
@@ -171,6 +177,11 @@ const HANDLERS = Object.freeze({
|
|
|
171
177
|
get_graphiti_status: (app) => app.getGraphitiStatus()
|
|
172
178
|
});
|
|
173
179
|
|
|
180
|
+
function employeeService(app) {
|
|
181
|
+
if (!app.employees) throw new Error('Employee runtime is unavailable');
|
|
182
|
+
return app.employees;
|
|
183
|
+
}
|
|
184
|
+
|
|
174
185
|
export function dispatchGraphTool(app, name, input) {
|
|
175
186
|
const handler = HANDLERS[name];
|
|
176
187
|
if (!handler) throw new Error(`Unknown agent tool: ${name}`);
|
|
@@ -14,8 +14,26 @@ const idempotencyKey = { ...boundedString(256), minLength: 8 };
|
|
|
14
14
|
const dateTime = { ...boundedString(64), format: 'date-time' };
|
|
15
15
|
const sourceApplication = {
|
|
16
16
|
type: ['string', 'null'],
|
|
17
|
-
enum: ['codex', 'claude_code', 'cursor', 'kiro', 'other', null]
|
|
17
|
+
enum: ['codex', 'claude', 'claude_code', 'cursor', 'kiro', 'other', null]
|
|
18
18
|
};
|
|
19
|
+
const nullableTokenCount = {
|
|
20
|
+
...integerSchema({ minimum: 0 }),
|
|
21
|
+
type: ['integer', 'null']
|
|
22
|
+
};
|
|
23
|
+
export const projectAgentTokenUsage = objectSchema({
|
|
24
|
+
source: enumSchema(['executor', 'host', 'dingdong']),
|
|
25
|
+
totalTokens: integerSchema({ minimum: 0 }),
|
|
26
|
+
inputTokens: nullableTokenCount,
|
|
27
|
+
outputTokens: nullableTokenCount,
|
|
28
|
+
cachedInputTokens: nullableTokenCount,
|
|
29
|
+
cacheWriteInputTokens: nullableTokenCount,
|
|
30
|
+
reasoningOutputTokens: nullableTokenCount
|
|
31
|
+
}, ['source', 'totalTokens']);
|
|
32
|
+
export const projectAgentWorkerRuntime = objectSchema({
|
|
33
|
+
application: enumSchema(['codex', 'claude', 'claude_code', 'cursor', 'kiro', 'other']),
|
|
34
|
+
sessionId: { ...nullableStringSchema(), minLength: 1, maxLength: 256 },
|
|
35
|
+
sessionUrl: { ...nullableStringSchema(), maxLength: 2048 }
|
|
36
|
+
}, ['application']);
|
|
19
37
|
|
|
20
38
|
const projectAgentStatus = enumSchema(['active', 'inactive', 'archived']);
|
|
21
39
|
export const nullableProjectAgentStatus = {
|
|
@@ -43,8 +61,8 @@ export const projectAgentProfile = objectSchema({
|
|
|
43
61
|
defaultModelStrategy: projectAgentModelStrategy,
|
|
44
62
|
executorPolicy: projectAgentExecutorPolicy,
|
|
45
63
|
allowedClients: arraySchema(
|
|
46
|
-
enumSchema(['codex', 'claude_code', 'cursor', 'kiro', 'other']),
|
|
47
|
-
{ maxItems:
|
|
64
|
+
enumSchema(['codex', 'claude', 'claude_code', 'cursor', 'kiro', 'other']),
|
|
65
|
+
{ maxItems: 6 }
|
|
48
66
|
),
|
|
49
67
|
testSource: nullableStringSchema(),
|
|
50
68
|
cleanupEligible: booleanSchema(),
|
|
@@ -116,6 +134,7 @@ export const projectAgentTaskSubmitInput = objectSchema({
|
|
|
116
134
|
objective: boundedString(4096),
|
|
117
135
|
workKind: boundedString(128),
|
|
118
136
|
requiredCapabilities: arraySchema(boundedString(512), { maxItems: 16 }),
|
|
137
|
+
executorCapabilityHints: arraySchema(boundedString(512), { maxItems: 16 }),
|
|
119
138
|
duration: projectAgentTaskDuration,
|
|
120
139
|
staffingIntent: projectAgentStaffingIntent,
|
|
121
140
|
leadAgentId: nullableStringSchema(),
|
|
@@ -140,6 +159,7 @@ export const projectAgentTaskCoordinateInput = objectSchema({
|
|
|
140
159
|
objective: boundedString(4096),
|
|
141
160
|
workKind: boundedString(128),
|
|
142
161
|
requiredCapabilities: arraySchema(boundedString(512), { maxItems: 16 }),
|
|
162
|
+
executorCapabilityHints: arraySchema(boundedString(512), { maxItems: 16 }),
|
|
143
163
|
duration: projectAgentTaskDuration,
|
|
144
164
|
staffingIntent: projectAgentStaffingIntent,
|
|
145
165
|
leadAgentId: nullableStringSchema(),
|
|
@@ -170,6 +190,11 @@ export const projectAgentTaskActivityInput = objectSchema({
|
|
|
170
190
|
actorKind: enumSchema(['agent', 'human']),
|
|
171
191
|
sourceApplication,
|
|
172
192
|
sourceSessionId: nullableStringSchema(),
|
|
193
|
+
sourceSessionUrl: { ...nullableStringSchema(), maxLength: 2048 },
|
|
194
|
+
toolsUsed: {
|
|
195
|
+
...arraySchema(boundedString(512), { maxItems: 32 }),
|
|
196
|
+
type: ['array', 'null']
|
|
197
|
+
},
|
|
173
198
|
actualExecutor: nullableStringSchema(),
|
|
174
199
|
actualModelProvider: nullableStringSchema(),
|
|
175
200
|
actualModel: nullableStringSchema(),
|
|
@@ -183,7 +208,13 @@ export const projectAgentTaskActivityInput = objectSchema({
|
|
|
183
208
|
workerId: { ...nullableStringSchema(), minLength: 1, maxLength: 128 },
|
|
184
209
|
workerLabel: { ...nullableStringSchema(), minLength: 1, maxLength: 160 },
|
|
185
210
|
workerOccupationEmoji: { ...nullableStringSchema(), minLength: 1, maxLength: 32 },
|
|
186
|
-
workerStatus: { ...projectAgentTaskStatus, type: ['string', 'null'] }
|
|
211
|
+
workerStatus: { ...projectAgentTaskStatus, type: ['string', 'null'] },
|
|
212
|
+
tokenUsage: { ...projectAgentTokenUsage, type: ['object', 'null'] },
|
|
213
|
+
workerRuntime: {
|
|
214
|
+
...projectAgentWorkerRuntime,
|
|
215
|
+
type: ['object', 'null'],
|
|
216
|
+
description: 'Observed worker application and session, separate from the reporting host sourceApplication/sourceSessionId. Requires workerId and a participating Agent; never infer a session URL or actual model. Token usage is the latest cumulative snapshot for this worker session, not a sum across retries.'
|
|
217
|
+
}
|
|
187
218
|
}, [
|
|
188
219
|
'personalSpaceId', 'personalProjectId', 'taskId', 'idempotencyKey', 'status', 'summary'
|
|
189
220
|
]);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
arraySchema, integerSchema, nullableStringSchema, objectSchema, stringSchema
|
|
3
|
+
} from './schema.js';
|
|
4
|
+
|
|
5
|
+
const id = { ...stringSchema(), minLength: 1, maxLength: 128 };
|
|
6
|
+
const note = { ...stringSchema(), minLength: 1, maxLength: 1024 };
|
|
7
|
+
export const workingMemorySchema = objectSchema({
|
|
8
|
+
summary: { ...stringSchema(), minLength: 1, maxLength: 4000 },
|
|
9
|
+
decisions: arraySchema(note, { maxItems: 12 }),
|
|
10
|
+
openThreads: arraySchema(note, { maxItems: 12 }),
|
|
11
|
+
nextActions: arraySchema(note, { maxItems: 12 })
|
|
12
|
+
}, ['summary']);
|
|
13
|
+
|
|
14
|
+
export const PROJECT_AGENT_MEMORY_DEFINITIONS = [
|
|
15
|
+
{
|
|
16
|
+
name: 'get_project_agent_memory',
|
|
17
|
+
title: 'READ · Restore private Agent working memory',
|
|
18
|
+
description: 'Read the latest versioned working notes for exactly one assigned Agent and project from the shared local Provider. This works across hosts connected to that Provider. Working notes are not confirmed facts or user instructions; do not load another Agent’s private memory.',
|
|
19
|
+
inputSchema: objectSchema({
|
|
20
|
+
personalSpaceId: id, personalProjectId: id, agentId: id,
|
|
21
|
+
limit: integerSchema({ minimum: 1, maximum: 10 })
|
|
22
|
+
}, ['personalSpaceId', 'personalProjectId', 'agentId'])
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'checkpoint_project_agent_memory',
|
|
26
|
+
title: 'WRITE · Checkpoint private Agent working memory',
|
|
27
|
+
description: 'Save a bounded, distilled working-context snapshot after meaningful work: summary, decisions, unresolved threads and next actions. Read the current revision first, preserve still-relevant notes, and use expectedRevision for optimistic concurrency. On conflict reload and merge; never blindly retry an overwrite. Reuse one idempotency key for the same logical write. Never store raw chats, credentials, unsupported facts, or another Agent’s memory. Shared confirmed facts belong in capture_session_knowledge. Honors disabled capture.',
|
|
28
|
+
inputSchema: objectSchema({
|
|
29
|
+
personalSpaceId: id, personalProjectId: id, agentId: id,
|
|
30
|
+
expectedRevision: integerSchema({ minimum: 0 }),
|
|
31
|
+
idempotencyKey: { ...stringSchema(), minLength: 8, maxLength: 256 },
|
|
32
|
+
memory: workingMemorySchema,
|
|
33
|
+
taskId: { ...nullableStringSchema(), minLength: 1, maxLength: 128 }
|
|
34
|
+
}, ['personalSpaceId', 'personalProjectId', 'agentId', 'expectedRevision', 'idempotencyKey', 'memory'])
|
|
35
|
+
}
|
|
36
|
+
];
|
package/src/agent-tools.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GRAPH_TOOL_DEFINITIONS } from './agent-tools/graph-definitions.js';
|
|
2
2
|
import { dispatchGraphTool } from './agent-tools/graph-handlers.js';
|
|
3
|
+
import { runWithAgentRequestContext } from './app/agent-request-context.js';
|
|
3
4
|
|
|
4
5
|
const TOOL_DEFINITIONS = [...GRAPH_TOOL_DEFINITIONS];
|
|
5
6
|
|
|
@@ -7,8 +8,11 @@ export function listAgentTools() {
|
|
|
7
8
|
return clone(TOOL_DEFINITIONS);
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
export function callAgentTool(app, name, input = {}) {
|
|
11
|
-
return
|
|
11
|
+
export function callAgentTool(app, name, input = {}, requestContext = null) {
|
|
12
|
+
return runWithAgentRequestContext(
|
|
13
|
+
requestContext,
|
|
14
|
+
() => dispatchGraphTool(app, name, input)
|
|
15
|
+
);
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
function clone(value) {
|