fuli-context 0.4.0 → 0.7.2
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.en.md +5 -0
- package/README.md +411 -173
- package/README.zh-CN.md +448 -0
- package/compose.graphiti.yml +6 -6
- package/dist/web/assets/AboutPage-DXh7Fwxt.css +1 -0
- package/dist/web/assets/AboutPage-DfnZo7Lo.js +1 -0
- package/dist/web/assets/ConnectionsPage-BloaSKmt.js +1 -0
- package/dist/web/assets/ConnectionsPage-CBHAdZXT.css +1 -0
- package/dist/web/assets/KnowledgeInspector-Bjhdu2mf.css +1 -0
- package/dist/web/assets/KnowledgeInspector-QvNpv0_k.js +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-Cx1w1jb2.css +1 -0
- package/dist/web/assets/KnowledgeOrganizerPage-DKq1jVD5.js +1 -0
- package/dist/web/assets/KnowledgePage-BWL0jT01.js +1 -0
- package/dist/web/assets/KnowledgeWorkspace-Czq6aZ7b.js +4 -0
- package/dist/web/assets/OverviewPage-5sJoO1Gh.js +1 -0
- package/dist/web/assets/{PersonalProfilePage-S8ZcG2LU.css → PersonalProfilePage-CdmEzyvZ.css} +1 -1
- package/dist/web/assets/PersonalProfilePage-tVChM9ik.js +1 -0
- package/dist/web/assets/PersonalProjectsPage-BPFrup4V.js +1 -0
- package/dist/web/assets/PublicProjectsPage-BPJSeREN.js +1 -0
- package/dist/web/assets/ReviewPage-B7EN817i.js +1 -0
- package/dist/web/assets/SearchableSelect-ClLN0rIb.js +1 -0
- package/dist/web/assets/SettingsPage-C6ouU0sR.css +1 -0
- package/dist/web/assets/SettingsPage-Chd_B3eH.js +1 -0
- package/dist/web/assets/_plugin-vue_export-helper-BDNMzG2s.js +1 -0
- package/dist/web/assets/console-CbDsKrsO.js +1 -0
- package/dist/web/assets/fuli-logo-Bu9WBuQe.js +1 -0
- package/dist/web/assets/fuli-logo-ER1wQ8Kk.png +0 -0
- package/dist/web/assets/i18n-BQcns1PH.js +5 -0
- package/dist/web/assets/identity-B8K4VYg6.js +1 -0
- package/dist/web/assets/index-CB8Xmsc2.js +2 -0
- package/dist/web/assets/index-CZeuPh-U.css +1 -0
- package/dist/web/assets/model-eF52GgPF.js +1 -0
- package/dist/web/assets/paths-hwz-Ac1g.js +1 -0
- package/dist/web/assets/useMinimumLoadingDisplay-BpCyBeko.css +1 -0
- package/dist/web/assets/useMinimumLoadingDisplay-wCgGDmHg.js +1 -0
- package/dist/web/assets/vue-router-BsEp_XwI.js +1 -0
- package/dist/web/index.html +9 -6
- package/docs/external-knowledge-architecture.md +279 -0
- package/examples/external-knowledge/markdown-folder.mjs +235 -0
- package/graph-provider/fuli_graph/app.py +57 -1
- package/graph-provider/fuli_graph/graph_models.py +3 -0
- package/graph-provider/fuli_graph/graph_query.py +62 -16
- package/graph-provider/fuli_graph/knowledge_review.py +612 -0
- package/graph-provider/fuli_graph/knowledge_review_models.py +127 -0
- package/graph-provider/fuli_graph/knowledge_search.py +51 -4
- package/graph-provider/fuli_graph/models.py +19 -0
- package/graph-provider/fuli_graph/runtime.py +15 -0
- package/graph-provider/fuli_graph/store_knowledge.py +2 -1
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +5 -407
- package/package.json +7 -4
- package/skills/capturing-session-knowledge/SKILL.md +24 -4
- package/skills/flreview/SKILL.md +73 -0
- package/skills/flreview/agents/openai.yaml +6 -0
- package/src/agent-tools/graph-definitions.js +79 -4
- package/src/agent-tools/graph-handlers.js +12 -0
- package/src/cli/command-registry.js +3 -3
- package/src/cli/local-runtime-command.js +60 -23
- package/src/cli/local-runtime-options.js +16 -6
- package/src/cli/setup-agent-selection.js +12 -12
- package/src/cli/setup-command.js +41 -18
- package/src/cli/shell-argument.js +10 -0
- package/src/cli/uninstall-command.js +17 -15
- package/src/cli/update-command.js +38 -30
- package/src/external-knowledge/catalog.js +61 -0
- package/src/external-knowledge/conflict-policy.js +58 -0
- package/src/external-knowledge/connected-search.js +166 -0
- package/src/external-knowledge/connectors/custom.js +133 -0
- package/src/external-knowledge/connectors/feishu.js +461 -0
- package/src/external-knowledge/connectors/mcp.js +438 -0
- package/src/external-knowledge/connectors/notion.js +307 -0
- package/src/external-knowledge/connectors/retrieval-api.js +222 -0
- package/src/external-knowledge/document-mapping.js +151 -0
- package/src/external-knowledge/graph-projection.js +17 -0
- package/src/external-knowledge/index.js +8 -0
- package/src/external-knowledge/registry.js +91 -0
- package/src/external-knowledge/runtime.js +68 -0
- package/src/external-knowledge/safe-diagnostic.js +14 -0
- package/src/external-knowledge/service.js +811 -0
- package/src/graphiti/agent-knowledge-workflows.js +7 -2
- package/src/graphiti/federated-application.js +66 -41
- package/src/graphiti/knowledge-item-role.js +21 -0
- package/src/graphiti/knowledge-review.js +43 -0
- package/src/graphiti/project-profile-mapping.js +32 -0
- package/src/graphiti/provider-client.js +22 -1
- package/src/graphiti/source-marker.js +54 -3
- package/src/graphiti/task-knowledge-recall.js +250 -0
- package/src/http/api-router.js +23 -108
- package/src/http/external-knowledge-api-router.js +104 -0
- package/src/http/graph-api-router.js +12 -1
- package/src/http/request-policy.js +38 -3
- package/src/local-runtime/lifecycle.js +37 -16
- package/src/mcp/create-mcp-server.js +1 -0
- package/src/mcp/instructions.js +7 -7
- package/src/mcp/tool-annotations.js +6 -0
- package/src/mcp/tool-result.js +1 -0
- package/src/server/application-lifecycle.js +2 -11
- package/src/server/blocked-ports.js +11 -0
- package/src/server/lan-access.js +52 -0
- package/src/server.js +103 -25
- package/src/setup/agent-installation-status.js +2 -1
- package/src/setup/agents.js +2 -1
- package/src/setup/claude-code-config.js +2 -1
- package/src/setup/codex-bootstrap.js +12 -7
- package/src/setup/container-runtime.js +25 -21
- package/src/setup/graph-runtime.js +219 -58
- package/src/setup/node-runtime.js +3 -3
- package/src/setup/options.js +2 -4
- package/src/setup/paths.js +18 -3
- package/src/setup/review-skill-adapters.js +49 -0
- package/src/setup/setup.js +26 -2
- package/src/setup/uninstall.js +4 -2
- package/src/system/resource-monitor.js +317 -0
- package/src/system/runtime-settings.js +131 -0
- package/src/system/system-service.js +119 -0
- package/dist/web/assets/ConnectionsPage-CCKWm-6p.js +0 -1
- package/dist/web/assets/KnowledgeInspector-BZkB2wJn.js +0 -1
- package/dist/web/assets/KnowledgeInspector-CrGYxEob.css +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-CJCNI2Wd.css +0 -1
- package/dist/web/assets/KnowledgeOrganizerPage-PXH-TlGt.js +0 -1
- package/dist/web/assets/KnowledgePage-CNQXd15y.js +0 -1
- package/dist/web/assets/KnowledgeWorkspace-CXPE4GCD.js +0 -4
- package/dist/web/assets/OverviewPage-ul7g7HXh.js +0 -1
- package/dist/web/assets/PersonalProfilePage-CC40Pw2L.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-CPIEcShD.js +0 -1
- package/dist/web/assets/PublicProjectsPage-C700sR7z.js +0 -1
- package/dist/web/assets/ReviewPage-7MDDUDgA.js +0 -1
- package/dist/web/assets/console-B_Ena2DS.js +0 -5
- package/dist/web/assets/fuli-logo-DGuyqchQ.png +0 -0
- package/dist/web/assets/identity-CjBwYSMX.js +0 -1
- package/dist/web/assets/index-BQRkOwPx.js +0 -2
- package/dist/web/assets/index-CpLDx3of.css +0 -1
- package/dist/web/assets/model-C-5RVIJ2.js +0 -1
- package/dist/web/assets/paths-BkULqmGI.js +0 -1
- package/dist/web/assets/vue-router-DnD3hUm7.js +0 -1
- package/src/agent/candidate-read-service.js +0 -53
- package/src/agent/context-pack-service.js +0 -83
- package/src/agent/public-read-policy.js +0 -39
- package/src/agent/public-read-service.js +0 -69
- package/src/agent/read-projection.js +0 -107
- package/src/agent/search-service.js +0 -61
- package/src/agent/space-boundary.js +0 -33
- package/src/app/bootstrap.js +0 -8
- package/src/app/create-application.js +0 -143
- package/src/app/state-service.js +0 -38
- package/src/candidates.js +0 -78
- package/src/classifier.js +0 -63
- package/src/cli/command-arguments.js +0 -14
- package/src/context-pack.js +0 -206
- package/src/extractor.js +0 -77
- package/src/fact-history.js +0 -39
- package/src/facts/fact-service.js +0 -89
- package/src/http/bounded-json-array.js +0 -19
- package/src/http/lens-route.js +0 -50
- package/src/ingestion.js +0 -161
- package/src/lens/lens-correction-service.js +0 -81
- package/src/lens/lens-fact-writer.js +0 -85
- package/src/lens/lens-input.js +0 -62
- package/src/lens/lens-query-projection.js +0 -87
- package/src/lens/lens-query-ranking.js +0 -62
- package/src/lens/lens-query.js +0 -143
- package/src/lens/lens-resource-projection.js +0 -93
- package/src/lens/lens-resource-selection.js +0 -45
- package/src/lens/lens-resource-service.js +0 -103
- package/src/lens/lens-search-query.js +0 -122
- package/src/lens/lens-service.js +0 -183
- package/src/models.js +0 -44
- package/src/observer.js +0 -83
- package/src/project-rules.js +0 -33
- package/src/publication/outbox-service.js +0 -46
- package/src/publication/publication-envelope-schema.js +0 -75
- package/src/publication/publication-envelope.js +0 -37
- package/src/publication/publication-policy.js +0 -82
- package/src/publication/publication-service.js +0 -48
- package/src/router.js +0 -58
- package/src/runtime-options.js +0 -138
- package/src/security/episode-visibility.js +0 -14
- package/src/security/fact-visibility.js +0 -15
- package/src/security/source-metadata-policy.js +0 -8
- package/src/storage/episode-evidence-preview.js +0 -100
- package/src/storage/fact-search-order.js +0 -18
- package/src/storage/file/episode-evidence.js +0 -37
- package/src/storage/file/episode-index.js +0 -59
- package/src/storage/file/fact-search.js +0 -60
- package/src/storage/file-store.js +0 -437
- package/src/storage/migrate.js +0 -128
- package/src/storage/migrations/001-initial.sql +0 -83
- package/src/storage/migrations/002-storage-integrity.sql +0 -113
- package/src/storage/record-validation.js +0 -46
- package/src/storage/snapshot-defaults.js +0 -54
- package/src/storage/sqlite/candidates-repository.js +0 -84
- package/src/storage/sqlite/episode-evidence-repository.js +0 -154
- package/src/storage/sqlite/episode-privacy-sql.js +0 -33
- package/src/storage/sqlite/episodes-repository.js +0 -52
- package/src/storage/sqlite/fact-search-repository.js +0 -162
- package/src/storage/sqlite/facts-repository.js +0 -146
- package/src/storage/sqlite/imports-repository.js +0 -39
- package/src/storage/sqlite/mapper.js +0 -84
- package/src/storage/sqlite/open-database.js +0 -15
- package/src/storage/sqlite/outbox-repository.js +0 -103
- package/src/storage/sqlite/snapshot-repository.js +0 -69
- package/src/storage/sqlite/spaces-repository.js +0 -52
- package/src/storage/sqlite/subscriptions-repository.js +0 -54
- package/src/storage/sqlite-store.js +0 -159
- package/src/storage/stable-json.js +0 -24
- package/src/storage/store-port.js +0 -20
- package/src/store.js +0 -2
|
@@ -2,9 +2,14 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
|
|
3
3
|
import { onlineSourceUri } from './source-uri.js';
|
|
4
4
|
|
|
5
|
-
export async function beginTaskContext(application, {
|
|
5
|
+
export async function beginTaskContext(application, {
|
|
6
|
+
sessionId,
|
|
7
|
+
projectPath,
|
|
8
|
+
taskPrompt = null
|
|
9
|
+
}) {
|
|
6
10
|
const preferences = await application.getCollaborationPreferences({
|
|
7
11
|
projectPath,
|
|
12
|
+
taskPrompt,
|
|
8
13
|
agentInvocation: true,
|
|
9
14
|
agentToolName: 'begin_task_context'
|
|
10
15
|
});
|
|
@@ -19,7 +24,7 @@ export async function beginTaskContext(application, { sessionId, projectPath })
|
|
|
19
24
|
previous_checkpoint_missing: task.previousCheckpointMissing,
|
|
20
25
|
...preferences,
|
|
21
26
|
task_guidance: {
|
|
22
|
-
retrieval: '
|
|
27
|
+
retrieval: 'Inspect task_knowledge_recall before asking for a stable project fact or method again. On a miss, use search_current_project_knowledge with focused action, artifact, target-system, or identifier queries; never use the full conversational request as the only query.',
|
|
23
28
|
checkpoint: 'Before finishing, call checkpoint_task_knowledge with capture_candidates or retain_nothing.'
|
|
24
29
|
}
|
|
25
30
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { dirname } from 'node:path';
|
|
2
|
+
|
|
1
3
|
import { GraphitiProviderClient } from './provider-client.js';
|
|
2
4
|
import {
|
|
3
5
|
canonicalProviderUrl,
|
|
@@ -22,8 +24,15 @@ import {
|
|
|
22
24
|
createFuliSourceMarker,
|
|
23
25
|
sourceConsoleUrl
|
|
24
26
|
} from './source-marker.js';
|
|
27
|
+
import {
|
|
28
|
+
recallTaskKnowledge,
|
|
29
|
+
TASK_KNOWLEDGE_RETRIEVAL_GUIDANCE
|
|
30
|
+
} from './task-knowledge-recall.js';
|
|
25
31
|
import { resolvePersonalProjectPath } from './project-path-context.js';
|
|
32
|
+
import { mergeExternalKnowledgeProjection } from '../external-knowledge/graph-projection.js';
|
|
26
33
|
import { TaskContextRegistry } from '../mcp/task-context-registry.js';
|
|
34
|
+
import { attachExternalKnowledgeRuntime } from '../external-knowledge/runtime.js';
|
|
35
|
+
import { resolveSetupPaths } from '../setup/paths.js';
|
|
27
36
|
import {
|
|
28
37
|
agentProjectResolution,
|
|
29
38
|
beginTaskContext as beginTaskContextWorkflow,
|
|
@@ -40,19 +49,27 @@ import {
|
|
|
40
49
|
providerConfirmationBasis,
|
|
41
50
|
providerEpisode
|
|
42
51
|
} from './knowledge-provider-mapping.js';
|
|
52
|
+
import { providerProjectProfile } from './project-profile-mapping.js';
|
|
53
|
+
import {
|
|
54
|
+
finishKnowledgeReview as finishKnowledgeReviewWorkflow,
|
|
55
|
+
listKnowledgeReviewCandidates as listKnowledgeReviewCandidatesWorkflow,
|
|
56
|
+
recordKnowledgeReviewProgress as recordKnowledgeReviewProgressWorkflow,
|
|
57
|
+
startKnowledgeReview as startKnowledgeReviewWorkflow
|
|
58
|
+
} from './knowledge-review.js';
|
|
43
59
|
|
|
44
60
|
export function openFederatedGraphApplication({
|
|
45
61
|
runtimeConfigPath,
|
|
46
62
|
config,
|
|
47
63
|
capturePolicyStore,
|
|
48
64
|
agentAccessPolicyStore,
|
|
49
|
-
fetchImpl = globalThis.fetch
|
|
65
|
+
fetchImpl = globalThis.fetch,
|
|
66
|
+
env = process.env
|
|
50
67
|
}) {
|
|
51
68
|
const resolved = config ?? readGraphRuntimeConfig(runtimeConfigPath);
|
|
52
69
|
const policyStore = capturePolicyStore ?? new CapturePolicyStore(
|
|
53
70
|
capturePolicyPathForRuntime(runtimeConfigPath)
|
|
54
71
|
);
|
|
55
|
-
|
|
72
|
+
const app = new FederatedGraphApplication(resolved, {
|
|
56
73
|
fetchImpl,
|
|
57
74
|
capturePolicyStore: policyStore,
|
|
58
75
|
agentAccessPolicyStore: agentAccessPolicyStore ?? new AgentAccessPolicyStore(
|
|
@@ -60,6 +77,14 @@ export function openFederatedGraphApplication({
|
|
|
60
77
|
),
|
|
61
78
|
consoleUrl: sourceConsoleUrl(runtimeConfigPath)
|
|
62
79
|
});
|
|
80
|
+
if (typeof runtimeConfigPath === 'string' && runtimeConfigPath) {
|
|
81
|
+
attachExternalKnowledgeRuntime(app, {
|
|
82
|
+
paths: resolveSetupPaths({ dataDir: dirname(runtimeConfigPath) }),
|
|
83
|
+
env,
|
|
84
|
+
fetchImpl
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return app;
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
export class FederatedGraphApplication {
|
|
@@ -163,6 +188,7 @@ export class FederatedGraphApplication {
|
|
|
163
188
|
async getCollaborationPreferences({
|
|
164
189
|
personalProjectId = null,
|
|
165
190
|
projectPath = null,
|
|
191
|
+
taskPrompt = null,
|
|
166
192
|
limit = 100,
|
|
167
193
|
agentInvocation = false,
|
|
168
194
|
agentToolName = 'get_collaboration_preferences'
|
|
@@ -188,6 +214,9 @@ export class FederatedGraphApplication {
|
|
|
188
214
|
result,
|
|
189
215
|
queuedConflicts
|
|
190
216
|
);
|
|
217
|
+
const taskKnowledgeRecall = taskPrompt === null
|
|
218
|
+
? null
|
|
219
|
+
: await recallTaskKnowledge(this, projectResolution, taskPrompt);
|
|
191
220
|
if (agentInvocation) {
|
|
192
221
|
const items = [
|
|
193
222
|
...(result.global_preferences ?? []),
|
|
@@ -207,14 +236,16 @@ export class FederatedGraphApplication {
|
|
|
207
236
|
conflicts: 'Do not apply entries listed in conflicts until the user resolves them.',
|
|
208
237
|
deferred_conflicts: 'If the current task would use a deferred_conflict, call resolve_deferred_preference_conflict before applying either side. Ignore unrelated deferred conflicts. The resolution must preserve the AI audit marker.',
|
|
209
238
|
authority: 'Human or authoritative-source confirmed preferences outrank agent-confirmed preferences. Agent-confirmed preferences are usable but lower priority and remain explicitly marked.',
|
|
210
|
-
pending: 'Pending preferences are available only through on-demand knowledge search; invalid and unrelated-project preferences are excluded. Automatic preference injection never counts as usage evidence.'
|
|
239
|
+
pending: 'Pending preferences are available only through on-demand knowledge search; invalid and unrelated-project preferences are excluded. Automatic preference injection never counts as usage evidence.',
|
|
240
|
+
knowledge_retrieval: TASK_KNOWLEDGE_RETRIEVAL_GUIDANCE
|
|
211
241
|
};
|
|
212
242
|
if (!agentInvocation) {
|
|
213
243
|
return {
|
|
214
244
|
...result,
|
|
215
245
|
deferred_conflicts: deferredConflicts,
|
|
216
246
|
application_guidance: applicationGuidance,
|
|
217
|
-
project_resolution: agentProjectResolution(projectResolution)
|
|
247
|
+
project_resolution: agentProjectResolution(projectResolution),
|
|
248
|
+
...(taskKnowledgeRecall ? { task_knowledge_recall: taskKnowledgeRecall } : {})
|
|
218
249
|
};
|
|
219
250
|
}
|
|
220
251
|
return {
|
|
@@ -222,6 +253,7 @@ export class FederatedGraphApplication {
|
|
|
222
253
|
.map(agentCollaborationPreference),
|
|
223
254
|
deferred_conflicts: deferredConflicts.map(agentDeferredPreferenceConflict),
|
|
224
255
|
application_guidance: applicationGuidance,
|
|
256
|
+
...(taskKnowledgeRecall ? { task_knowledge_recall: taskKnowledgeRecall } : {}),
|
|
225
257
|
context: {
|
|
226
258
|
personal_space_id: result.personal_space_id,
|
|
227
259
|
personal_project_id: result.personal_project_id,
|
|
@@ -293,7 +325,9 @@ export class FederatedGraphApplication {
|
|
|
293
325
|
if (!['bounded', 'all_local_confirmed'].includes(personalProjectScope)) {
|
|
294
326
|
throw new TypeError('Unknown personal project search scope');
|
|
295
327
|
}
|
|
296
|
-
const subscriptions =
|
|
328
|
+
const subscriptions = projectIds.length
|
|
329
|
+
? await this.personal.listSubscriptions(personalSpaceId)
|
|
330
|
+
: [];
|
|
297
331
|
const requestedProjects = new Set(projectIds);
|
|
298
332
|
const selectedSubscriptions = subscriptions.filter(({ project_id: projectId }) =>
|
|
299
333
|
requestedProjects.has(projectId)
|
|
@@ -451,6 +485,7 @@ export class FederatedGraphApplication {
|
|
|
451
485
|
providerUrl = null,
|
|
452
486
|
personalProjectId = null,
|
|
453
487
|
limit = 500,
|
|
488
|
+
offset = null,
|
|
454
489
|
agentInvocation = false,
|
|
455
490
|
agentToolName = 'get_knowledge_graph'
|
|
456
491
|
}) {
|
|
@@ -458,19 +493,42 @@ export class FederatedGraphApplication {
|
|
|
458
493
|
if (spaceId !== this.config.personal.spaceId) {
|
|
459
494
|
throw new TypeError('A configured providerUrl is required for a team-shared project graph');
|
|
460
495
|
}
|
|
461
|
-
const result = await this.personal.graph(
|
|
496
|
+
const result = await this.personal.graph(
|
|
497
|
+
spaceId,
|
|
498
|
+
limit,
|
|
499
|
+
personalProjectId,
|
|
500
|
+
offset
|
|
501
|
+
);
|
|
462
502
|
if (agentInvocation) {
|
|
463
503
|
await this.#recordAgentViews([
|
|
464
504
|
...result.nodes.map(({ id }) => ({ item_id: id, item_kind: 'entity' })),
|
|
465
505
|
...result.edges.map(({ id }) => ({ item_id: id, item_kind: 'relationship' }))
|
|
466
506
|
], agentToolName);
|
|
467
507
|
}
|
|
468
|
-
return
|
|
508
|
+
return mergeExternalKnowledgeProjection(
|
|
509
|
+
this.externalKnowledge, result, spaceId, personalProjectId
|
|
510
|
+
);
|
|
469
511
|
}
|
|
470
512
|
if (personalProjectId) {
|
|
471
513
|
throw new TypeError('Personal project scope cannot be used with a team-shared provider');
|
|
472
514
|
}
|
|
473
|
-
return this.#workspace(providerUrl).client.graph(spaceId, limit);
|
|
515
|
+
return this.#workspace(providerUrl).client.graph(spaceId, limit, null, offset);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async startKnowledgeReview(input) {
|
|
519
|
+
return startKnowledgeReviewWorkflow(this, input);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async listKnowledgeReviewCandidates(input) {
|
|
523
|
+
return listKnowledgeReviewCandidatesWorkflow(this, input);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async recordKnowledgeReviewProgress(input) {
|
|
527
|
+
return recordKnowledgeReviewProgressWorkflow(this, input);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async finishKnowledgeReview(input) {
|
|
531
|
+
return finishKnowledgeReviewWorkflow(this, input);
|
|
474
532
|
}
|
|
475
533
|
|
|
476
534
|
async recordKnowledgeUsage({
|
|
@@ -1203,39 +1261,6 @@ function assertSafeKnowledgeMutation(input) {
|
|
|
1203
1261
|
}
|
|
1204
1262
|
}
|
|
1205
1263
|
|
|
1206
|
-
function providerProjectProfile(profile) {
|
|
1207
|
-
if (!profile || typeof profile !== 'object') throw new TypeError('Project profile is required');
|
|
1208
|
-
const assessment = profile.assessment ? sanitizeProjectAssessment(profile.assessment) : null;
|
|
1209
|
-
return {
|
|
1210
|
-
name: profile.name,
|
|
1211
|
-
purpose: profile.purpose ?? null,
|
|
1212
|
-
scope: profile.scope ?? null,
|
|
1213
|
-
technical_summary: profile.technical_summary ?? profile.technicalSummary ?? null,
|
|
1214
|
-
lifecycle: profile.lifecycle ?? 'planned',
|
|
1215
|
-
sources: profile.sources ?? [],
|
|
1216
|
-
boundaries: profile.boundaries ?? [],
|
|
1217
|
-
assessment
|
|
1218
|
-
};
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
function sanitizeProjectAssessment(input) {
|
|
1222
|
-
const assessment = {
|
|
1223
|
-
score: input.score,
|
|
1224
|
-
label: input.label,
|
|
1225
|
-
confirmed: input.confirmed ?? [],
|
|
1226
|
-
inferred: input.inferred ?? [],
|
|
1227
|
-
dimensions: (input.dimensions ?? []).map((dimension) => ({
|
|
1228
|
-
key: dimension.key,
|
|
1229
|
-
label: dimension.label,
|
|
1230
|
-
score: dimension.score,
|
|
1231
|
-
state: dimension.state === 'missing' ? 'inferred' : dimension.state,
|
|
1232
|
-
evidence: dimension.evidence ?? []
|
|
1233
|
-
})),
|
|
1234
|
-
analyzed_at: input.analyzed_at ?? input.analyzedAt
|
|
1235
|
-
};
|
|
1236
|
-
return assessment;
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
1264
|
function groupSubscriptions(subscriptions) {
|
|
1240
1265
|
const grouped = new Map();
|
|
1241
1266
|
for (const subscription of subscriptions) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const SUPPORTING_ENTITY_TYPES = new Set([
|
|
2
|
+
'DecisionOption',
|
|
3
|
+
'DecisionRationale',
|
|
4
|
+
'ValidationResult'
|
|
5
|
+
]);
|
|
6
|
+
|
|
7
|
+
const SUPPORTING_RELATIONSHIPS = new Set([
|
|
8
|
+
'MOTIVATED_BY',
|
|
9
|
+
'REJECTED_OPTION',
|
|
10
|
+
'VALIDATED_BY'
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
export function knowledgeItemRole(item) {
|
|
14
|
+
if (
|
|
15
|
+
SUPPORTING_ENTITY_TYPES.has(item?.type)
|
|
16
|
+
|| SUPPORTING_RELATIONSHIPS.has(item?.relationship)
|
|
17
|
+
) {
|
|
18
|
+
return 'supporting';
|
|
19
|
+
}
|
|
20
|
+
return 'primary';
|
|
21
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export function startKnowledgeReview(app, input) {
|
|
2
|
+
assertActivePersonalSpace(app, input.personalSpaceId);
|
|
3
|
+
return app.personal.startKnowledgeReview({
|
|
4
|
+
personal_space_id: input.personalSpaceId,
|
|
5
|
+
scope: input.scope,
|
|
6
|
+
personal_project_id: input.personalProjectId ?? null
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function listKnowledgeReviewCandidates(app, input) {
|
|
11
|
+
assertActivePersonalSpace(app, input.personalSpaceId);
|
|
12
|
+
return app.personal.listKnowledgeReviewCandidates({
|
|
13
|
+
personal_space_id: input.personalSpaceId,
|
|
14
|
+
review_id: input.reviewId,
|
|
15
|
+
limit: input.limit
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function recordKnowledgeReviewProgress(app, input) {
|
|
20
|
+
assertActivePersonalSpace(app, input.personalSpaceId);
|
|
21
|
+
return app.personal.recordKnowledgeReviewProgress({
|
|
22
|
+
personal_space_id: input.personalSpaceId,
|
|
23
|
+
review_id: input.reviewId,
|
|
24
|
+
candidate_key: input.candidateKey,
|
|
25
|
+
outcome: input.outcome,
|
|
26
|
+
note: input.note ?? null
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function finishKnowledgeReview(app, input) {
|
|
31
|
+
assertActivePersonalSpace(app, input.personalSpaceId);
|
|
32
|
+
return app.personal.finishKnowledgeReview({
|
|
33
|
+
personal_space_id: input.personalSpaceId,
|
|
34
|
+
review_id: input.reviewId,
|
|
35
|
+
disposition: input.disposition
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function assertActivePersonalSpace(app, personalSpaceId) {
|
|
40
|
+
if (personalSpaceId !== app.config.personal.spaceId) {
|
|
41
|
+
throw new TypeError('Knowledge review must use the active personal space');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function providerProjectProfile(profile) {
|
|
2
|
+
if (!profile || typeof profile !== 'object') {
|
|
3
|
+
throw new TypeError('Project profile is required');
|
|
4
|
+
}
|
|
5
|
+
return {
|
|
6
|
+
name: profile.name,
|
|
7
|
+
purpose: profile.purpose ?? null,
|
|
8
|
+
scope: profile.scope ?? null,
|
|
9
|
+
technical_summary: profile.technical_summary ?? profile.technicalSummary ?? null,
|
|
10
|
+
lifecycle: profile.lifecycle ?? 'planned',
|
|
11
|
+
sources: profile.sources ?? [],
|
|
12
|
+
boundaries: profile.boundaries ?? [],
|
|
13
|
+
assessment: profile.assessment ? providerProjectAssessment(profile.assessment) : null
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function providerProjectAssessment(input) {
|
|
18
|
+
return {
|
|
19
|
+
score: input.score,
|
|
20
|
+
label: input.label,
|
|
21
|
+
confirmed: input.confirmed ?? [],
|
|
22
|
+
inferred: input.inferred ?? [],
|
|
23
|
+
dimensions: (input.dimensions ?? []).map((dimension) => ({
|
|
24
|
+
key: dimension.key,
|
|
25
|
+
label: dimension.label,
|
|
26
|
+
score: dimension.score,
|
|
27
|
+
state: dimension.state === 'missing' ? 'inferred' : dimension.state,
|
|
28
|
+
evidence: dimension.evidence ?? []
|
|
29
|
+
})),
|
|
30
|
+
analyzed_at: input.analyzed_at ?? input.analyzedAt
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -118,6 +118,26 @@ export class GraphitiProviderClient {
|
|
|
118
118
|
commit(input) {
|
|
119
119
|
return this.#request('/v1/knowledge/commits', { method: 'POST', body: input });
|
|
120
120
|
}
|
|
121
|
+
startKnowledgeReview(input) {
|
|
122
|
+
return this.#request('/v1/knowledge/reviews/start', {
|
|
123
|
+
method: 'POST', body: input
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
listKnowledgeReviewCandidates(input) {
|
|
127
|
+
return this.#request('/v1/knowledge/reviews/candidates', {
|
|
128
|
+
method: 'POST', body: input
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
recordKnowledgeReviewProgress(input) {
|
|
132
|
+
return this.#request('/v1/knowledge/reviews/progress', {
|
|
133
|
+
method: 'POST', body: input
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
finishKnowledgeReview(input) {
|
|
137
|
+
return this.#request('/v1/knowledge/reviews/finish', {
|
|
138
|
+
method: 'POST', body: input
|
|
139
|
+
});
|
|
140
|
+
}
|
|
121
141
|
reviseKnowledgeItem(itemId, input) {
|
|
122
142
|
return this.#request(`/v1/knowledge/items/${encodeURIComponent(itemId)}`, {
|
|
123
143
|
method: 'PATCH', body: input
|
|
@@ -240,9 +260,10 @@ export class GraphitiProviderClient {
|
|
|
240
260
|
if (personalProjectId) query.set('personal_project_id', personalProjectId);
|
|
241
261
|
return this.#request(`/v1/collaboration-preferences?${query}`);
|
|
242
262
|
}
|
|
243
|
-
graph(spaceId, limit = 500, personalProjectId = null) {
|
|
263
|
+
graph(spaceId, limit = 500, personalProjectId = null, offset = null) {
|
|
244
264
|
const query = new URLSearchParams({ limit: String(limit) });
|
|
245
265
|
if (personalProjectId) query.set('personal_project_id', personalProjectId);
|
|
266
|
+
if (offset !== null) query.set('offset', String(offset));
|
|
246
267
|
return this.#request(`/v1/spaces/${encodeURIComponent(spaceId)}/graph?${query}`);
|
|
247
268
|
}
|
|
248
269
|
|
|
@@ -2,8 +2,10 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { dirname, join, resolve } from 'node:path';
|
|
3
3
|
|
|
4
4
|
import { DEFAULT_FULI_PORT } from '../defaults.js';
|
|
5
|
+
import { knowledgeItemRole } from './knowledge-item-role.js';
|
|
5
6
|
|
|
6
7
|
const MAX_CITATIONS = 1;
|
|
8
|
+
const PROJECT_SCOPE_PRIORITY_BOOST = 1;
|
|
7
9
|
const DEFAULT_CONSOLE_URL = `http://127.0.0.1:${DEFAULT_FULI_PORT}`;
|
|
8
10
|
|
|
9
11
|
export function sourceConsoleUrl(runtimeConfigPath, {
|
|
@@ -22,12 +24,16 @@ export function sourceConsoleUrl(runtimeConfigPath, {
|
|
|
22
24
|
export function createFuliSourceMarker({
|
|
23
25
|
consoleUrl = DEFAULT_CONSOLE_URL,
|
|
24
26
|
facts = [],
|
|
25
|
-
entities = []
|
|
27
|
+
entities = [],
|
|
28
|
+
projectScopePriority = 'balanced'
|
|
26
29
|
} = {}) {
|
|
30
|
+
const comparePriority = projectScopePriority === 'strict'
|
|
31
|
+
? compareStrictProjectCitationPriority
|
|
32
|
+
: compareCitationPriority;
|
|
27
33
|
const citations = uniqueCitations([
|
|
28
34
|
...facts.map(factCitation),
|
|
29
35
|
...entities.map(entityCitation)
|
|
30
|
-
].filter(Boolean));
|
|
36
|
+
].filter(Boolean)).sort(comparePriority);
|
|
31
37
|
const status = citations.length ? 'matched' : 'no_match';
|
|
32
38
|
return {
|
|
33
39
|
required: true,
|
|
@@ -45,6 +51,10 @@ function factCitation(fact) {
|
|
|
45
51
|
spaceId: fact.spaceId ?? fact.space_id,
|
|
46
52
|
itemKind: 'relationship',
|
|
47
53
|
itemId: fact.id,
|
|
54
|
+
definedProjectId: fact.defined_project_id,
|
|
55
|
+
scopeDistance: fact.scope_distance,
|
|
56
|
+
score: fact.score,
|
|
57
|
+
role: knowledgeItemRole(fact),
|
|
48
58
|
title: [fact.source_entity, fact.target_entity].filter(Boolean).join(' → ') ||
|
|
49
59
|
fact.fact || '关系知识'
|
|
50
60
|
});
|
|
@@ -56,21 +66,62 @@ function entityCitation(entity) {
|
|
|
56
66
|
spaceId: entity.spaceId ?? entity.space_id,
|
|
57
67
|
itemKind: 'entity',
|
|
58
68
|
itemId: entity.id,
|
|
69
|
+
definedProjectId: entity.defined_project_id,
|
|
70
|
+
scopeDistance: entity.scope_distance,
|
|
71
|
+
score: entity.score,
|
|
72
|
+
role: knowledgeItemRole(entity),
|
|
59
73
|
title: entity.name || entity.summary || '实体知识'
|
|
60
74
|
});
|
|
61
75
|
}
|
|
62
76
|
|
|
63
|
-
function citation({
|
|
77
|
+
function citation({
|
|
78
|
+
scope,
|
|
79
|
+
spaceId,
|
|
80
|
+
itemKind,
|
|
81
|
+
itemId,
|
|
82
|
+
definedProjectId,
|
|
83
|
+
scopeDistance,
|
|
84
|
+
score,
|
|
85
|
+
role,
|
|
86
|
+
title
|
|
87
|
+
}) {
|
|
64
88
|
if (!['personal', 'project'].includes(scope) || !spaceId || !itemId) return null;
|
|
65
89
|
return {
|
|
66
90
|
scope,
|
|
67
91
|
spaceId: String(spaceId),
|
|
68
92
|
itemKind,
|
|
69
93
|
itemId: String(itemId),
|
|
94
|
+
projectScoped: Boolean(definedProjectId),
|
|
95
|
+
scopeDistance: Number(scopeDistance ?? 0),
|
|
96
|
+
score: Number(score ?? 0),
|
|
97
|
+
role,
|
|
70
98
|
title: singleLine(title)
|
|
71
99
|
};
|
|
72
100
|
}
|
|
73
101
|
|
|
102
|
+
function compareCitationPriority(left, right) {
|
|
103
|
+
return citationPriority(right) - citationPriority(left);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function compareStrictProjectCitationPriority(left, right) {
|
|
107
|
+
if (left.projectScoped !== right.projectScoped) {
|
|
108
|
+
return Number(right.projectScoped) - Number(left.projectScoped);
|
|
109
|
+
}
|
|
110
|
+
if (left.projectScoped && left.scopeDistance !== right.scopeDistance) {
|
|
111
|
+
return left.scopeDistance - right.scopeDistance;
|
|
112
|
+
}
|
|
113
|
+
if (left.role !== right.role) {
|
|
114
|
+
return left.role === 'primary' ? -1 : 1;
|
|
115
|
+
}
|
|
116
|
+
return compareCitationPriority(left, right);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function citationPriority(value) {
|
|
120
|
+
const projectBoost = value.projectScoped ? PROJECT_SCOPE_PRIORITY_BOOST : 0;
|
|
121
|
+
const distancePenalty = Math.min(Math.max(value.scopeDistance, 0), 8) * 0.15;
|
|
122
|
+
return value.score + projectBoost - distancePenalty;
|
|
123
|
+
}
|
|
124
|
+
|
|
74
125
|
function uniqueCitations(citations) {
|
|
75
126
|
const seen = new Set();
|
|
76
127
|
return citations.filter(({ scope, spaceId, itemKind, itemId }) => {
|