fuli-context 0.7.2 → 0.7.4-beta.1
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 +173 -21
- package/README.zh-CN.md +146 -12
- package/compose.graphiti.yml +2 -0
- package/dist/web/assets/{AboutPage-DfnZo7Lo.js → AboutPage-CftRexSY.js} +1 -1
- package/dist/web/assets/{ConnectionsPage-BloaSKmt.js → ConnectionsPage-D5J91x6d.js} +1 -1
- package/dist/web/assets/{useMinimumLoadingDisplay-BpCyBeko.css → KnowledgeEditDialog-DWUV_NPp.css} +1 -1
- package/dist/web/assets/KnowledgeEditDialog-wotVahvr.js +1 -0
- package/dist/web/assets/{KnowledgeInspector-Bjhdu2mf.css → KnowledgeInspector--1NujtXW.css} +1 -1
- package/dist/web/assets/KnowledgeInspector-BzkW0mVs.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-BebUDiHt.js +1 -0
- package/dist/web/assets/KnowledgePage-OUT07aKH.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-1pHJ0MNZ.js +4 -0
- package/dist/web/assets/OverviewPage-CHE6XhdS.js +1 -0
- package/dist/web/assets/PersonalProfilePage-B7T09bow.css +1 -0
- package/dist/web/assets/PersonalProfilePage-CXXiabUy.js +1 -0
- package/dist/web/assets/PersonalProjectsPage-d2wYGW8n.js +1 -0
- package/dist/web/assets/PublicProjectsPage-hxLShtnZ.js +1 -0
- package/dist/web/assets/{ReviewPage-B7EN817i.js → ReviewPage-DUeyu7E8.js} +1 -1
- package/dist/web/assets/{SearchableSelect-ClLN0rIb.js → SearchableSelect-C5RiB5F8.js} +1 -1
- package/dist/web/assets/SettingsPage-BMuASSzQ.js +1 -0
- package/dist/web/assets/SettingsPage-CAfz4qiV.css +1 -0
- package/dist/web/assets/WritingTastePage-B9BCYIwQ.js +1 -0
- package/dist/web/assets/WritingTastePage-DSgvTH6x.css +1 -0
- package/dist/web/assets/{console-CbDsKrsO.js → console-DMvHxKf9.js} +1 -1
- package/dist/web/assets/conversation-launcher-settings-Dnlcw7Rj.js +1 -0
- package/dist/web/assets/{i18n-BQcns1PH.js → i18n-CWfd8Dtt.js} +1 -1
- package/dist/web/assets/{identity-B8K4VYg6.js → identity-C9mLdR8L.js} +1 -1
- package/dist/web/assets/index-F5e2sQ7p.js +2 -0
- package/dist/web/assets/index-X2j29j8i.css +1 -0
- package/dist/web/assets/{model-eF52GgPF.js → model-CsYAR8O3.js} +1 -1
- package/dist/web/assets/paths-CDREouhi.js +1 -0
- package/dist/web/assets/useApi-CROJJdhE-BLQiPVw0.js +1 -0
- package/dist/web/assets/vue-router-DN8x6iY1.js +1 -0
- package/dist/web/index.html +7 -6
- package/graph-provider/fuli_graph/app.py +238 -2
- package/graph-provider/fuli_graph/auth.py +18 -0
- package/graph-provider/fuli_graph/collaboration_context.py +253 -17
- package/graph-provider/fuli_graph/common_knowledge.py +6 -2
- package/graph-provider/fuli_graph/config.py +5 -0
- package/graph-provider/fuli_graph/graph_models.py +6 -0
- package/graph-provider/fuli_graph/graph_projection.py +14 -0
- package/graph-provider/fuli_graph/graph_query.py +27 -3
- package/graph-provider/fuli_graph/knowledge_management.py +19 -1
- package/graph-provider/fuli_graph/knowledge_review.py +49 -4
- package/graph-provider/fuli_graph/knowledge_review_models.py +11 -5
- package/graph-provider/fuli_graph/knowledge_search.py +11 -0
- package/graph-provider/fuli_graph/models.py +15 -2
- package/graph-provider/fuli_graph/personal_global_preference_models.py +234 -0
- package/graph-provider/fuli_graph/personal_global_preferences.py +1247 -0
- package/graph-provider/fuli_graph/project_action_models.py +22 -0
- package/graph-provider/fuli_graph/project_knowledge.py +121 -2
- package/graph-provider/fuli_graph/provider_values.py +24 -0
- package/graph-provider/fuli_graph/runtime.py +78 -0
- package/graph-provider/fuli_graph/search_projection.py +14 -1
- package/graph-provider/fuli_graph/store_knowledge.py +116 -2
- package/graph-provider/fuli_graph/workflow_candidate_models.py +168 -0
- package/graph-provider/fuli_graph/workflow_candidates.py +996 -0
- package/graph-provider/fuli_graph/workflow_observation_models.py +30 -0
- package/graph-provider/fuli_graph/workflow_observations.py +84 -0
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +4 -4
- package/skills/capturing-session-knowledge/SKILL.md +32 -5
- package/skills/flreview/SKILL.md +68 -40
- package/skills/flreview/agents/openai.yaml +2 -2
- package/src/agent-tools/graph-definitions.js +140 -24
- package/src/agent-tools/graph-handlers.js +10 -4
- package/src/cli/command-registry.js +1 -1
- package/src/cli/local-runtime-command.js +69 -2
- package/src/graphiti/agent-knowledge-workflows.js +497 -16
- package/src/graphiti/collaboration-preference-projection.js +162 -0
- package/src/graphiti/federated-application.js +157 -162
- package/src/graphiti/federated-search-support.js +102 -0
- package/src/graphiti/knowledge-provider-mapping.js +15 -0
- package/src/graphiti/provider-client.js +162 -10
- package/src/graphiti/related-project-suggestions.js +109 -0
- package/src/graphiti/runtime-config.js +14 -0
- package/src/graphiti/source-marker.js +2 -2
- package/src/graphiti/user-taste-skill.js +241 -0
- package/src/graphiti/workflow-candidate-mapping.js +87 -0
- package/src/graphiti/workflow-observation.js +82 -0
- package/src/graphiti/writing-taste-profile-workflow.js +25 -0
- package/src/graphiti/writing-taste-profile.js +490 -0
- package/src/http/graph-api-router.js +15 -2
- package/src/mcp/context-resources.js +158 -0
- package/src/mcp/create-mcp-server.js +41 -5
- package/src/mcp/instructions.js +5 -7
- package/src/mcp/session-id.js +60 -0
- package/src/mcp/task-context-registry.js +15 -3
- package/src/mcp/tool-annotations.js +8 -1
- package/src/mcp/tool-result.js +28 -4
- package/src/server.js +0 -1
- package/src/setup/claude-code-config.js +17 -6
- package/src/setup/graph-runtime.js +20 -2
- package/src/system/runtime-settings.js +121 -2
- package/src/system/system-service.js +5 -1
- package/README.en.md +0 -5
- package/dist/web/assets/KnowledgeInspector-QvNpv0_k.js +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-DKq1jVD5.js +0 -1
- package/dist/web/assets/KnowledgePage-BWL0jT01.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-Czq6aZ7b.js +0 -4
- package/dist/web/assets/OverviewPage-5sJoO1Gh.js +0 -1
- package/dist/web/assets/PersonalProfilePage-CdmEzyvZ.css +0 -1
- package/dist/web/assets/PersonalProfilePage-tVChM9ik.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-BPFrup4V.js +0 -1
- package/dist/web/assets/PublicProjectsPage-BPJSeREN.js +0 -1
- package/dist/web/assets/SettingsPage-C6ouU0sR.css +0 -1
- package/dist/web/assets/SettingsPage-Chd_B3eH.js +0 -1
- package/dist/web/assets/index-CB8Xmsc2.js +0 -2
- package/dist/web/assets/index-CZeuPh-U.css +0 -1
- package/dist/web/assets/paths-hwz-Ac1g.js +0 -1
- package/dist/web/assets/useMinimumLoadingDisplay-wCgGDmHg.js +0 -1
- package/dist/web/assets/vue-router-BsEp_XwI.js +0 -1
|
@@ -82,7 +82,10 @@ const epistemicFields = {
|
|
|
82
82
|
epistemicStatus,
|
|
83
83
|
confirmationStatus,
|
|
84
84
|
confirmationBasis,
|
|
85
|
-
reasoningSummary:
|
|
85
|
+
reasoningSummary: {
|
|
86
|
+
...nullableStringSchema(),
|
|
87
|
+
description: 'Required and nonempty whenever originQuadrant is not known_known. Explain how the item became known; omitting it rejects the whole batch.'
|
|
88
|
+
},
|
|
86
89
|
profileAspect,
|
|
87
90
|
inheritanceMode,
|
|
88
91
|
inheritedProjectIds: arraySchema(id, { maxItems: 32 })
|
|
@@ -188,6 +191,40 @@ const commonKnowledgePromotionRequired = [
|
|
|
188
191
|
'personalSpaceId', 'parentProjectId', 'itemKind', 'canonicalItemId',
|
|
189
192
|
'duplicateItemIds', 'reason', 'humanConfirmationReason'
|
|
190
193
|
];
|
|
194
|
+
const personalGlobalPreferenceDecisionIntent = {
|
|
195
|
+
personalSpaceId: id,
|
|
196
|
+
candidateId: {
|
|
197
|
+
...boundedString(64),
|
|
198
|
+
pattern: '^personal-global-[a-f0-9]{20}$'
|
|
199
|
+
},
|
|
200
|
+
candidateVersion: {
|
|
201
|
+
...boundedString(32),
|
|
202
|
+
pattern: '^v1:[a-f0-9]{24}$'
|
|
203
|
+
},
|
|
204
|
+
decisionRevision: integerSchema({ minimum: 0 }),
|
|
205
|
+
decision: enumSchema(['approve', 'reject']),
|
|
206
|
+
sourceItems: arraySchema(objectSchema({
|
|
207
|
+
itemId: id,
|
|
208
|
+
itemKind: knowledgeItemKind,
|
|
209
|
+
projectId: id
|
|
210
|
+
}, ['itemId', 'itemKind', 'projectId']), { minItems: 2, maxItems: 32 }),
|
|
211
|
+
preferenceKey: boundedString(512),
|
|
212
|
+
targetScope: enumSchema(['parent_project', 'personal_global']),
|
|
213
|
+
targetProjectId: nullableStringSchema(),
|
|
214
|
+
profileAspect,
|
|
215
|
+
globalTitle: { type: ['string', 'null'], minLength: 1, maxLength: 512 },
|
|
216
|
+
globalInstruction: { type: ['string', 'null'], minLength: 1, maxLength: 8192 },
|
|
217
|
+
humanConfirmationReason: boundedString(4096),
|
|
218
|
+
confirmedAt: dateTime,
|
|
219
|
+
sessionId: id,
|
|
220
|
+
idempotencyKey: id
|
|
221
|
+
};
|
|
222
|
+
const personalGlobalPreferenceDecisionRequired = [
|
|
223
|
+
'personalSpaceId', 'candidateId', 'candidateVersion', 'decisionRevision',
|
|
224
|
+
'decision', 'sourceItems', 'preferenceKey', 'targetScope',
|
|
225
|
+
'targetProjectId', 'humanConfirmationReason',
|
|
226
|
+
'confirmedAt', 'sessionId', 'idempotencyKey'
|
|
227
|
+
];
|
|
191
228
|
const captureEpisodeFields = {
|
|
192
229
|
idempotencyKey: id,
|
|
193
230
|
name: label,
|
|
@@ -207,6 +244,11 @@ const captureEpisodeRequired = [
|
|
|
207
244
|
'idempotencyKey', 'name', 'sourceKind', 'sourceDescription',
|
|
208
245
|
'referenceTime', 'entities', 'relationships'
|
|
209
246
|
];
|
|
247
|
+
const workflowObservedStep = objectSchema({
|
|
248
|
+
actionId: id,
|
|
249
|
+
name: label,
|
|
250
|
+
summary: nullableStringSchema()
|
|
251
|
+
}, ['actionId', 'name']);
|
|
210
252
|
|
|
211
253
|
export const GRAPH_TOOL_DEFINITIONS = [
|
|
212
254
|
{
|
|
@@ -247,6 +289,17 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
247
289
|
limit: integerSchema({ minimum: 1, maximum: 200 })
|
|
248
290
|
}, ['projectPath'])
|
|
249
291
|
},
|
|
292
|
+
{
|
|
293
|
+
name: 'get_user_taste_skill',
|
|
294
|
+
title: 'READ · Generate the current user-taste Skill',
|
|
295
|
+
description: 'Generate a bounded, read-only user-taste Skill projection from the effective personal preferences for the exact active project. It uses prior confirmed and explicitly agent-confirmed preference data to provide task-specific recommendations, labels evidence status and scope, preserves the current-request and authoritative-constraint precedence, and never overwrites a user-authored taste Skill or promotes a pending inference. Call it when a UI, writing, product, architecture, code, or other judgment call would benefit from the user\'s established taste.',
|
|
296
|
+
inputSchema: objectSchema({
|
|
297
|
+
projectPath: boundedString(4096),
|
|
298
|
+
taskPrompt: boundedString(8192),
|
|
299
|
+
personalProjectId: nullableStringSchema(),
|
|
300
|
+
limit: integerSchema({ minimum: 1, maximum: 200 })
|
|
301
|
+
}, ['projectPath'])
|
|
302
|
+
},
|
|
250
303
|
{
|
|
251
304
|
name: 'resolve_deferred_preference_conflict',
|
|
252
305
|
description: 'Resolve one AI-deferred collaboration-preference conflict returned by get_collaboration_preferences when, and only when, the current task needs that preference. Compare both confirmed sides against their evidence and the current context before choosing. The operation updates the effective knowledge, preserves revision history, and permanently marks the conflict as previously conflicted and resolved by AI. Use merge with a canonical item and merged instruction, keep_left or keep_right to retain one side, or split_scope to move one side to an exact personal project.',
|
|
@@ -265,18 +318,49 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
265
318
|
},
|
|
266
319
|
{
|
|
267
320
|
name: 'capture_session_knowledge',
|
|
268
|
-
description: 'Silently batch durable session knowledge when the user-enabled capture policy allows it. When knowledge was read from an online source, sourceUri preserves the exact original HTTP(S) link so a capable Agent can re-read it later and refresh Fuli knowledge; it does not authorize source-document writeback. Every item records its discovery quadrant, structured confirmation basis, and pending or confirmed state. A disabled policy returns capture_disabled without writing. Personal profile knowledge stays personal; only project knowledge with an auditable confirmation can enter public review.',
|
|
321
|
+
description: 'Silently batch durable session knowledge when the user-enabled capture policy allows it. When knowledge was read from an online source, sourceUri preserves the exact original HTTP(S) link so a capable Agent can re-read it later and refresh Fuli knowledge; it does not authorize source-document writeback. Every item records its discovery quadrant, structured confirmation basis, and pending or confirmed state. reasoningSummary is required for every entity or relationship whose originQuadrant is not known_known. A disabled policy returns capture_disabled without writing. Personal profile knowledge stays personal; only project knowledge with an auditable confirmation can enter public review.',
|
|
269
322
|
inputSchema: objectSchema({
|
|
270
|
-
targetKind:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
323
|
+
targetKind: {
|
|
324
|
+
...enumSchema(['personal', 'project']),
|
|
325
|
+
description: 'Use "personal" for the personal graph, including knowledge scoped to a local personal project via personalProjectId. Use "project" only for a team-shared project queued for public review.'
|
|
326
|
+
},
|
|
327
|
+
spaceId: {
|
|
328
|
+
...id,
|
|
329
|
+
description: 'With targetKind "personal", the active personal space id. With targetKind "project", the team-shared project id.'
|
|
330
|
+
},
|
|
331
|
+
personalProjectId: {
|
|
332
|
+
...nullableStringSchema(),
|
|
333
|
+
description: 'Local personal project scope. Only meaningful with targetKind "personal".'
|
|
334
|
+
},
|
|
335
|
+
providerUrl: {
|
|
336
|
+
...nullableStringSchema(),
|
|
337
|
+
description: 'Required with targetKind "project" and ignored for "personal".'
|
|
338
|
+
},
|
|
274
339
|
sessionId: id,
|
|
275
340
|
...captureEpisodeFields
|
|
276
341
|
}, [
|
|
277
342
|
'targetKind', 'spaceId', 'sessionId', ...captureEpisodeRequired
|
|
278
343
|
])
|
|
279
344
|
},
|
|
345
|
+
{
|
|
346
|
+
name: 'record_workflow_transition_observation',
|
|
347
|
+
title: 'WRITE · Observe one completed workflow transition',
|
|
348
|
+
description: 'Record one Agent-reported completed X-to-Y action transition in the personal Provider. One call submits one observation; calls for the same project, X/Y, workflow key, condition, and MCP-host session deduplicate to one Episodic node. The Provider derives occurrence and distinct-session counts from persisted episodes. The MCP host attests session, time, and observation identity, not the truth of the reported actions. The tool does not accept aggregate counts, confirmation authority, approval, or durable-consent claims. Every observation remains pending behavioral evidence and is not user consent or execution authorization. Call it only after both actions completed successfully. This is an Agent/adapter observation seam, not automatic telemetry for arbitrary host tools.',
|
|
349
|
+
inputSchema: objectSchema({
|
|
350
|
+
personalSpaceId: id,
|
|
351
|
+
personalProjectId: nullableStringSchema(),
|
|
352
|
+
fromStep: workflowObservedStep,
|
|
353
|
+
toStep: workflowObservedStep,
|
|
354
|
+
workflowKey: id,
|
|
355
|
+
condition: attributes,
|
|
356
|
+
evidenceSummary: shortText,
|
|
357
|
+
sourceApplication,
|
|
358
|
+
sourceTurnId: { type: ['string', 'null'], minLength: 1, maxLength: 256 },
|
|
359
|
+
sensitivity: enumSchema(['normal', 'private', 'restricted'])
|
|
360
|
+
}, [
|
|
361
|
+
'personalSpaceId', 'fromStep', 'toStep', 'workflowKey', 'evidenceSummary'
|
|
362
|
+
])
|
|
363
|
+
},
|
|
280
364
|
{
|
|
281
365
|
name: 'record_decision_trace',
|
|
282
366
|
title: 'WRITE · Store a decision with its rationale',
|
|
@@ -322,7 +406,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
322
406
|
{
|
|
323
407
|
name: 'search_knowledge_graph',
|
|
324
408
|
title: 'READ · Search the scoped knowledge graph',
|
|
325
|
-
description: 'Search durable context before saying you do not know when a task may depend on remembered URLs, routes, requirements, architecture, prior decisions, runbooks, rationale, or personal preferences. Supporting facts and entities expose bounded source_uris when their evidence came from online sources, allowing a capable Agent to re-read the original source before refreshing Fuli knowledge. Pending knowledge is searchable and explicitly marked; agent-confirmed knowledge ranks below human-confirmed knowledge. The bounded scope includes the personal-global profile, exact active local project, selectively inheritable knowledge reached through PART_OF or USES_KNOWLEDGE_FROM, explicitly selected additional personal projects, and selected subscribed team projects. Generic RELATED_TO links never expand scope. Use all_local_confirmed only after explicit user confirmation; it searches registered local personal projects for this query and never expands public projects. If that still has no support, use read-only local file search in the current repository or workspace files within a safe root. The response includes sourceMarker for supporting results, noMatchSourceMarker when returned items do not support the answer, and retrievalGuidance with the required next action.',
|
|
409
|
+
description: 'Search durable context before saying you do not know when a task may depend on remembered URLs, routes, requirements, architecture, prior decisions, runbooks, rationale, or personal preferences. Supporting facts and entities expose bounded source_uris when their evidence came from online sources, allowing a capable Agent to re-read the original source before refreshing Fuli knowledge. Pending knowledge is searchable and explicitly marked; agent-confirmed knowledge ranks below human-confirmed knowledge. The bounded scope includes the personal-global profile, exact active local project, selectively inheritable knowledge reached through PART_OF or USES_KNOWLEDGE_FROM, explicitly selected additional personal projects, and selected subscribed team projects. Generic RELATED_TO links never expand scope. A result may instead include one-time read-only relatedProjectSuggestions only for active human-authorized RELATED_TO edges; ask the user before running the supplied exact-project follow-up query, and never silently add that project to future scope. Use all_local_confirmed only after explicit user confirmation; it searches registered local personal projects for this query and never expands public projects. If that still has no support, use read-only local file search in the current repository or workspace files within a safe root. The response includes sourceMarker for supporting results, noMatchSourceMarker when returned items do not support the answer, and retrievalGuidance with the required next action.',
|
|
326
410
|
inputSchema: objectSchema({
|
|
327
411
|
personalSpaceId: id,
|
|
328
412
|
query: shortText,
|
|
@@ -396,7 +480,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
396
480
|
{
|
|
397
481
|
name: 'search_current_project_knowledge',
|
|
398
482
|
title: 'READ · Search current project and its knowledge sources',
|
|
399
|
-
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.',
|
|
483
|
+
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.',
|
|
400
484
|
inputSchema: objectSchema({
|
|
401
485
|
projectPath: boundedString(4096),
|
|
402
486
|
queries: arraySchema(shortText, { minItems: 1, maxItems: 10 }),
|
|
@@ -418,6 +502,28 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
418
502
|
limitPerProject: integerSchema({ minimum: 1, maximum: 50 })
|
|
419
503
|
}, ['personalSpaceId', 'parentProjectId', 'query'])
|
|
420
504
|
},
|
|
505
|
+
{
|
|
506
|
+
name: 'discover_personal_global_preference_candidates',
|
|
507
|
+
title: 'READ · Find possible personal-global preferences',
|
|
508
|
+
description: 'Read-only scope-governance aid across two or more explicitly selected personal projects. It searches each exact project independently, excludes inherited and existing personal-global results, preserves every original preference text, qualifier, project source, and source URI, and exposes any shared lexical core only as a non-authoritative derived candidate. Similarity and weight never apply or promote a preference. Every candidate requires explicit human scope judgment through the candidate-bound review workflow.',
|
|
509
|
+
inputSchema: objectSchema({
|
|
510
|
+
personalSpaceId: id,
|
|
511
|
+
personalProjectIds: arraySchema(id, { minItems: 2, maxItems: 32 }),
|
|
512
|
+
query: shortText,
|
|
513
|
+
minProjects: integerSchema({ minimum: 2, maximum: 32 }),
|
|
514
|
+
similarityThreshold: numberSchema({ minimum: 0, maximum: 1 }),
|
|
515
|
+
limitPerProject: integerSchema({ minimum: 1, maximum: 50 })
|
|
516
|
+
}, ['personalSpaceId', 'personalProjectIds', 'query'])
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
name: 'preview_personal_global_preference_decision',
|
|
520
|
+
title: 'READ · Inspect a version-bound scope decision',
|
|
521
|
+
description: 'Read-only inspection for one exact personal-global preference candidate and decision revision. It revalidates every selected local source in the Provider and returns the preserved snapshots plus an exact payload fingerprint. It deliberately does not mint an approval token: an independent human-review client must confirm that fingerprint and mint the short-lived, one-time capability. The Agent cannot claim human authority through this tool.',
|
|
522
|
+
inputSchema: objectSchema(
|
|
523
|
+
personalGlobalPreferenceDecisionIntent,
|
|
524
|
+
personalGlobalPreferenceDecisionRequired
|
|
525
|
+
)
|
|
526
|
+
},
|
|
421
527
|
{
|
|
422
528
|
name: 'preview_common_knowledge_promotion',
|
|
423
529
|
title: 'CONFIRM · Preview parent-project promotion',
|
|
@@ -514,7 +620,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
514
620
|
{
|
|
515
621
|
name: 'record_knowledge_review_progress',
|
|
516
622
|
title: 'WRITE · Record one review outcome',
|
|
517
|
-
description: 'Record one user-authorized candidate outcome after any required knowledge mutation succeeds. confirmed keeps the item, updated/invalidated follow successful writes,
|
|
623
|
+
description: 'Record one user-authorized candidate outcome after any required knowledge mutation succeeds. confirmed keeps the item, updated/invalidated follow successful writes, deferred carries it into the next review, and delegated_to_ai follows a successful current-quadrant change to unknown_unknown.',
|
|
518
624
|
inputSchema: objectSchema({
|
|
519
625
|
personalSpaceId: id,
|
|
520
626
|
reviewId: id,
|
|
@@ -523,7 +629,7 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
523
629
|
pattern: '^(entity|relationship):.+'
|
|
524
630
|
},
|
|
525
631
|
outcome: enumSchema([
|
|
526
|
-
'confirmed', 'updated', 'invalidated', '
|
|
632
|
+
'confirmed', 'updated', 'invalidated', 'deferred', 'delegated_to_ai'
|
|
527
633
|
]),
|
|
528
634
|
note: nullableStringSchema()
|
|
529
635
|
}, ['personalSpaceId', 'reviewId', 'candidateKey', 'outcome'])
|
|
@@ -538,15 +644,37 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
538
644
|
disposition: enumSchema(['paused', 'completed'])
|
|
539
645
|
}, ['personalSpaceId', 'reviewId', 'disposition'])
|
|
540
646
|
},
|
|
647
|
+
{
|
|
648
|
+
name: 'list_workflow_candidates',
|
|
649
|
+
title: 'READ · List learned workflow candidates',
|
|
650
|
+
description: 'Read persisted X-to-Y workflow candidates and their condition, explainable occurrence count, distinct-session count, recency, confirmation authority, negative evidence, declines, review status, and durable authorization. candidateVersion changes only when the rule definition changes; evidenceRevision tracks added or changed evidence; decisionRevision tracks review/authorization state transitions, including reset after a rule change. Rejected candidates and evidence remain in history. This read never executes a step or grants authority.',
|
|
651
|
+
inputSchema: objectSchema({
|
|
652
|
+
personalSpaceId: id,
|
|
653
|
+
personalProjectId: nullableStringSchema(),
|
|
654
|
+
afterStepKey: nullableStringSchema(),
|
|
655
|
+
limit: integerSchema({ minimum: 1, maximum: 100 })
|
|
656
|
+
}, ['personalSpaceId'])
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
name: 'recommend_next_workflow_steps',
|
|
660
|
+
title: 'READ · Recommend what to ask after a workflow step',
|
|
661
|
+
description: 'Read persisted candidates matching the completed source step. Provider weights only decide whether a candidate crosses the recommendation threshold; they never grant execution authority. A recommended but unapproved candidate returns ask_user and must not execute Y. Even a durable authorization never replaces per-call approval for high-risk send, delete, publish, payment, or external-write tools.',
|
|
662
|
+
inputSchema: objectSchema({
|
|
663
|
+
personalSpaceId: id,
|
|
664
|
+
personalProjectId: nullableStringSchema(),
|
|
665
|
+
afterStepKey: id,
|
|
666
|
+
limit: integerSchema({ minimum: 1, maximum: 100 })
|
|
667
|
+
}, ['personalSpaceId', 'afterStepKey'])
|
|
668
|
+
},
|
|
541
669
|
{
|
|
542
670
|
name: 'revise_personal_knowledge',
|
|
543
|
-
description: '
|
|
671
|
+
description: 'Confirm, correct, invalidate, or restore one personal entity or relationship while preserving revision history and original evidence. This is the same personal-only operation used by the management UI.',
|
|
544
672
|
inputSchema: objectSchema({
|
|
545
673
|
personalSpaceId: id,
|
|
546
674
|
personalProjectId: nullableStringSchema(),
|
|
547
675
|
itemKind: knowledgeItemKind,
|
|
548
676
|
itemId: id,
|
|
549
|
-
action: enumSchema(['update', 'invalidate', 'restore']),
|
|
677
|
+
action: enumSchema(['confirm', 'update', 'invalidate', 'restore']),
|
|
550
678
|
reason: shortText,
|
|
551
679
|
name: nullableStringSchema(),
|
|
552
680
|
summary: nullableStringSchema(),
|
|
@@ -573,18 +701,6 @@ export const GRAPH_TOOL_DEFINITIONS = [
|
|
|
573
701
|
reason: shortText
|
|
574
702
|
}, ['personalSpaceId', 'itemKind', 'itemId', 'targetProjectId', 'reason'])
|
|
575
703
|
},
|
|
576
|
-
{
|
|
577
|
-
name: 'set_personal_preference_scope',
|
|
578
|
-
description: 'Change one taste, personality, or judgment preference between the default personal-global scope and one exact personal project. The source evidence remains unchanged and the scope change is recorded in revision history.',
|
|
579
|
-
inputSchema: objectSchema({
|
|
580
|
-
personalSpaceId: id,
|
|
581
|
-
itemKind: knowledgeItemKind,
|
|
582
|
-
itemId: id,
|
|
583
|
-
scope: enumSchema(['global', 'project']),
|
|
584
|
-
projectId: nullableStringSchema(),
|
|
585
|
-
reason: shortText
|
|
586
|
-
}, ['personalSpaceId', 'itemKind', 'itemId', 'scope', 'reason'])
|
|
587
|
-
},
|
|
588
704
|
{
|
|
589
705
|
name: 'preview_personal_project_action',
|
|
590
706
|
title: 'PREVIEW · Authorize a personal project write',
|
|
@@ -10,12 +10,15 @@ const HANDLERS = Object.freeze({
|
|
|
10
10
|
agentInvocation: true,
|
|
11
11
|
agentToolName: 'get_collaboration_preferences'
|
|
12
12
|
}),
|
|
13
|
+
get_user_taste_skill: (app, input) => app.getUserTasteSkill(input),
|
|
13
14
|
resolve_deferred_preference_conflict: (app, input) =>
|
|
14
15
|
app.resolveDeferredPreferenceConflict({
|
|
15
16
|
...input,
|
|
16
17
|
operationActor: 'agent'
|
|
17
18
|
}),
|
|
18
19
|
capture_session_knowledge: (app, input) => app.captureSessionKnowledge(input),
|
|
20
|
+
record_workflow_transition_observation: (app, input) =>
|
|
21
|
+
app.recordWorkflowTransitionObservation(input),
|
|
19
22
|
record_decision_trace: (app, input) => app.recordDecisionTrace(input),
|
|
20
23
|
search_knowledge_graph: (app, input) => app.searchKnowledge({
|
|
21
24
|
...input,
|
|
@@ -34,6 +37,10 @@ const HANDLERS = Object.freeze({
|
|
|
34
37
|
app.searchCurrentProjectKnowledge(input),
|
|
35
38
|
discover_common_knowledge_candidates: (app, input) =>
|
|
36
39
|
app.discoverCommonKnowledgeCandidates(input),
|
|
40
|
+
discover_personal_global_preference_candidates: (app, input) =>
|
|
41
|
+
app.discoverPersonalGlobalPreferenceCandidates(input),
|
|
42
|
+
preview_personal_global_preference_decision: (app, input) =>
|
|
43
|
+
app.previewPersonalGlobalPreferenceDecision(input),
|
|
37
44
|
preview_common_knowledge_promotion: (app, input) =>
|
|
38
45
|
app.previewCommonKnowledgePromotion(input),
|
|
39
46
|
apply_common_knowledge_promotion: (app, input) => {
|
|
@@ -65,6 +72,9 @@ const HANDLERS = Object.freeze({
|
|
|
65
72
|
record_knowledge_review_progress: (app, input) =>
|
|
66
73
|
app.recordKnowledgeReviewProgress(input),
|
|
67
74
|
finish_knowledge_review: (app, input) => app.finishKnowledgeReview(input),
|
|
75
|
+
list_workflow_candidates: (app, input) => app.listWorkflowCandidates(input),
|
|
76
|
+
recommend_next_workflow_steps: (app, input) =>
|
|
77
|
+
app.recommendNextWorkflowSteps(input),
|
|
68
78
|
revise_personal_knowledge: (app, input) => app.reviseKnowledgeItem({
|
|
69
79
|
...input,
|
|
70
80
|
operationActor: 'agent'
|
|
@@ -73,10 +83,6 @@ const HANDLERS = Object.freeze({
|
|
|
73
83
|
...input,
|
|
74
84
|
operationActor: 'agent'
|
|
75
85
|
}),
|
|
76
|
-
set_personal_preference_scope: (app, input) => app.setPersonalPreferenceScope({
|
|
77
|
-
...input,
|
|
78
|
-
operationActor: 'agent'
|
|
79
|
-
}),
|
|
80
86
|
preview_personal_project_action: (app, input) =>
|
|
81
87
|
app.previewKnowledgeProjectAction(input),
|
|
82
88
|
apply_personal_project_action: (app, input) => {
|
|
@@ -12,7 +12,7 @@ General:
|
|
|
12
12
|
--version, -v
|
|
13
13
|
|
|
14
14
|
Local service:
|
|
15
|
-
start [--port PORT] [--open] [--lan|--no-lan] [--rebuild] [--data-dir DIR] [--personal-space NAME]
|
|
15
|
+
start [--port PORT] [--open] [--lan|--no-lan] [--rebuild] [--data-dir DIR] [--personal-space NAME] (checks Agent setup)
|
|
16
16
|
stop [--data-dir DIR]
|
|
17
17
|
restart [--port PORT] [--open] [--lan|--no-lan] [--rebuild] [--data-dir DIR] [--personal-space NAME]
|
|
18
18
|
status [--json] [--data-dir DIR] [--port PORT]
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
startLocalRuntime,
|
|
6
6
|
stopLocalRuntime
|
|
7
7
|
} from '../local-runtime/lifecycle.js';
|
|
8
|
+
import { discoverAgents } from '../setup/agents.js';
|
|
9
|
+
import { inspectAgentInstallations } from '../setup/agent-installation-status.js';
|
|
8
10
|
import { resolveSetupPaths } from '../setup/paths.js';
|
|
9
11
|
import {
|
|
10
12
|
DEFAULT_RUNTIME_SETTINGS,
|
|
@@ -43,15 +45,28 @@ export async function runLocalRuntimeCommand(command, args, dependencies = {}) {
|
|
|
43
45
|
status: dependencies.inspect ?? inspectLocalRuntime,
|
|
44
46
|
open: dependencies.openConsole ?? openLocalConsole
|
|
45
47
|
};
|
|
48
|
+
const agentSetupCheck = command === 'start'
|
|
49
|
+
? checkAgentSetup({
|
|
50
|
+
paths,
|
|
51
|
+
env,
|
|
52
|
+
nodePath: dependencies.nodePath ?? process.execPath,
|
|
53
|
+
discover: dependencies.discoverAgents ?? discoverAgents,
|
|
54
|
+
inspect: dependencies.inspectAgentInstallations ?? inspectAgentInstallations
|
|
55
|
+
})
|
|
56
|
+
: null;
|
|
46
57
|
const result = await handlers[command](input, dependencies.lifecycleDependencies);
|
|
58
|
+
const outputResult = agentSetupCheck
|
|
59
|
+
? { ...result, agentSetupCheck }
|
|
60
|
+
: result;
|
|
47
61
|
|
|
48
62
|
if (command === 'status' && options.json) {
|
|
49
|
-
write(JSON.stringify(
|
|
63
|
+
write(JSON.stringify(outputResult, null, 2));
|
|
50
64
|
} else {
|
|
51
|
-
write(formatLocalRuntimeResult(command,
|
|
65
|
+
write(formatLocalRuntimeResult(command, outputResult));
|
|
52
66
|
}
|
|
53
67
|
return {
|
|
54
68
|
...result,
|
|
69
|
+
...(agentSetupCheck ? { agentSetupCheck } : {}),
|
|
55
70
|
exitCode: command === 'status' && result.status !== 'running'
|
|
56
71
|
? 1
|
|
57
72
|
: result.status === 'partial' ? 1 : 0
|
|
@@ -86,6 +101,8 @@ export function formatLocalRuntimeResult(command, result) {
|
|
|
86
101
|
|
|
87
102
|
function formatStartedRuntime(title, result) {
|
|
88
103
|
const lines = [title, `Management UI: ${result.url}`];
|
|
104
|
+
const agentSetupNotice = formatAgentSetupNotice(result.agentSetupCheck);
|
|
105
|
+
if (agentSetupNotice) lines.push(agentSetupNotice);
|
|
89
106
|
if (result.lan === true) {
|
|
90
107
|
lines.push(
|
|
91
108
|
'LAN URLs:',
|
|
@@ -98,6 +115,56 @@ function formatStartedRuntime(title, result) {
|
|
|
98
115
|
return lines.join('\n');
|
|
99
116
|
}
|
|
100
117
|
|
|
118
|
+
function checkAgentSetup({ paths, env, nodePath, discover, inspect }) {
|
|
119
|
+
try {
|
|
120
|
+
const agents = discover({ env }).filter(({ available }) => available);
|
|
121
|
+
if (!agents.length) return { status: 'checked', agents: [] };
|
|
122
|
+
const inspected = inspect(agents, {
|
|
123
|
+
nodePath,
|
|
124
|
+
mcpServerPath: paths.mcpServerPath,
|
|
125
|
+
runtimeConfigPath: paths.graphRuntimeConfigPath,
|
|
126
|
+
sessionSkillPath: paths.sessionSkillPath,
|
|
127
|
+
projectSkillPath: paths.projectSkillPath,
|
|
128
|
+
reviewSkillPath: paths.reviewSkillPath
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
status: 'checked',
|
|
132
|
+
agents: inspected.filter(({ integrationStatus }) => integrationStatus !== 'connected')
|
|
133
|
+
};
|
|
134
|
+
} catch {
|
|
135
|
+
return { status: 'unavailable', agents: [] };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function formatAgentSetupNotice(check) {
|
|
140
|
+
if (!check) return null;
|
|
141
|
+
if (check.status === 'unavailable') {
|
|
142
|
+
return [
|
|
143
|
+
'Could not verify Agent integrations.',
|
|
144
|
+
'Run `fuli setup` to verify and update them.'
|
|
145
|
+
].join('\n');
|
|
146
|
+
}
|
|
147
|
+
if (!check.agents.length) return null;
|
|
148
|
+
return [
|
|
149
|
+
'Agent setup required:',
|
|
150
|
+
...check.agents.map((agent) => ` ${agent.label}: ${agentNeedsSetup(agent)}`),
|
|
151
|
+
'Run `fuli setup` to install or update them.'
|
|
152
|
+
].join('\n');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function agentNeedsSetup(agent) {
|
|
156
|
+
const detailLabels = {
|
|
157
|
+
mcp: 'MCP',
|
|
158
|
+
skills: 'Skills',
|
|
159
|
+
bootstrap: 'Bootstrap',
|
|
160
|
+
lifecycleHooks: 'Lifecycle hooks'
|
|
161
|
+
};
|
|
162
|
+
const outdated = Object.entries(agent.integrationDetails ?? {})
|
|
163
|
+
.filter(([, status]) => status !== 'current')
|
|
164
|
+
.map(([key, status]) => `${detailLabels[key] ?? key}: ${status}`);
|
|
165
|
+
return outdated.join(', ') || 'integration update available';
|
|
166
|
+
}
|
|
167
|
+
|
|
101
168
|
function formatStatus(result) {
|
|
102
169
|
const labels = {
|
|
103
170
|
running: 'running',
|