@xopcai/xopc 0.0.374 → 0.0.375
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BrA20N2m.js → agent-avatar-dicebear-B2Popl59.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-BZrOdxou.js → agent-defaults-settings-panel-BnF3HrHY.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-plugin-dialog-B3ux1AhY.js → agent-plugin-dialog-CwP6OrUs.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-CXlXFU6M.js → agents-n3IremKl.js} +3 -3
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BXahEVPm.js → app-management-settings-panel-DNkXIPxK.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-CE2qJMkD.js → appearance-settings-p1_NpH8a.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-DGVOnCxZ.js → apps-page-CP2u5iEh.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BWL7eT4_.js → automations-page-CjYiGOov.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-BxIShhkZ.js → automations-workspace-BAHiUQbe.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-3n446-mX.js → block-editor-DiOou1HO.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-BmTK7Gtn.js → browser-automations-page-nArl2uwX.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-DBQ-WETQ.js → browser-settings-page-Bd8tF-gg.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-page-D-nQ6Zzi.js → capabilities-page-Cx4cdgse.js} +2 -2
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-Dx1fpBmH.js → capabilities-settings-panel-DpWceNd0.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-header-actions-BRMqvQVb.js → capability-header-actions-AeBubNQK.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-DXfEP1FR.js → channels-Cd1Rf0Vk.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-BRdzCjWO.js → chat-terminal-dock-DrVlbq_P.js} +1 -1
- package/dist/gateway/static/root/assets/{computer-settings-page-BhCHMRpD.js → computer-settings-page-TUzZnurj.js} +1 -1
- package/dist/gateway/static/root/assets/{connector-service-page-BXE8Z-Ll.js → connector-service-page-BlpwjGW7.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-D9RZjhw8.js → connectors-page-j8VFMD4o.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-BJ7N92wm.js → date-picker-CjKRpA8X.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-gyxCM-hb.js → dependency-picker-J9_0obij.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-B-WM4l-L.js → desktop-pet-DySwgreF.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-usJqcew5.js → desktop-pet-settings-B1-oyKBG.js} +1 -1
- package/dist/gateway/static/root/assets/{device-pairing-wizard-DoSR4DGk.js → device-pairing-wizard-C5rjPAyc.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DqVlV2YH.js → directory-picker-path-field-BY7MwiZd.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CUule9SU.js → extension-page-JoSFhfb6.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-_OFukkEJ.js → extension-settings-page-B7LtTNx7.js} +1 -1
- package/dist/gateway/static/root/assets/{fallback-models-CiSc3h8i.js → fallback-models-DKSWcBt_.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-qSUrpS1h.js → gateway-settings-CGm-lbsX.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-COjDsuzg.js → home-page-CX3uWkyH.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-DdvIj-ZL.js → imports-page-DS_RFtWf.js} +1 -1
- package/dist/gateway/static/root/assets/{index-DEaVabvo.js → index-CgvOIDy_.js} +5 -5
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DbqFlNsF.js → keyboard-shortcuts-settings-BxwXR2qA.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-REowUzkp.js → local-app-workbench-page-BWd4RMBE.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-DdCMNn_z.js → local-apps-page-BsgcA6-N.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-B_6fHDoi.js → logs-page-CLP5pu2j.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-D4vcSRE3.js → management-settings-CZAZwCpE.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-panel-B7U6EbAi.js → note-detail-panel-BeAHgdtw.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-page-BzHVaH8j.js → notes-page-MP21Zf_R.js} +1 -1
- package/dist/gateway/static/root/assets/{page-context-capture-button-D7Y4vFRN.js → page-context-capture-button-BZADmKcV.js} +1 -1
- package/dist/gateway/static/root/assets/{personal-page-E6huhFk4.js → personal-page-BbaTGmE-.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CK_czbBx.js → product-open-page-CBnKsW4p.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-CU6KlaVP.js → product-preview-content-B0gGexdG.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-c3ye2bdq.js → project-detail-page-ZjQSv_NG.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-BA1UuuRF.js → projects-page-Bf7Sd_Ck.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-D_FLVZAm.js → remote-access-hub-Bl8aPuXU.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Cxjmwdyf.js → runtime-tools-settings-panel-CQZ1c-re.js} +1 -1
- package/dist/gateway/static/root/assets/{scenes-page-Av47PHdM.js → scenes-page-1xGRBOJO.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-IM7QeSm3.js → schema-form-BYqugMox.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-Bol3ScEc.js → sessions-page-DjMSVXU3.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BJuMTtyI.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-BeVtwwVd.js → settings-page-CSqi5fmN.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-zTmrMwMm.js → setup-status-panel-D5bM0TvA.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-Bkhkt_6M.js → shares-settings-C-V9WllF.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-api-Dgwc707w.js → skill-api-CFtEHy5e.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-CFIte-vM.js → skills-page-B-olXUVH.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-Ck6zGDHb.js → system-settings-panel-DBMR9ks_.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-C3ZPEZqw.js → task-detail-page-CGe34vxR.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-CjxMpAm2.js → tunnel-api-CzNIlgdJ.js} +1 -1
- package/dist/gateway/static/root/assets/{usage-page-Dnhp9xQ4.js → usage-page-O3abwewp.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-Bx2JlCpj.js +2 -0
- package/dist/gateway/static/root/assets/{work-discovery-overlay-CVd_y3K2.js → work-discovery-overlay-D967-fVj.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Dwg40uGK.js → workflow-run-setup-panel-BJ945m7G.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-BQR4JdXB.js → workflows-page-DUpVeIuw.js} +1 -1
- package/dist/gateway/static/root/assets/{xopc-cloud-account-card-CaKc_J7j.js → xopc-cloud-account-card-Bq9ubffP.js} +1 -1
- package/dist/gateway/static/root/index.html +1 -1
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +2 -7
- package/dist/src/agent/agent-manager.js +24 -53
- package/dist/src/agent/background-review/coordinator.js +1 -1
- package/dist/src/agent/background-review/prompts.d.ts +6 -0
- package/dist/src/agent/background-review/prompts.js +7 -1
- package/dist/src/agent/background-review/run-background-review.d.ts +3 -0
- package/dist/src/agent/background-review/run-background-review.js +184 -16
- package/dist/src/agent/context/coordinator.d.ts +1 -0
- package/dist/src/agent/context/coordinator.js +11 -2
- package/dist/src/agent/context/execution-context.js +40 -4
- package/dist/src/agent/context/project-context.js +11 -3
- package/dist/src/agent/embedded/model-runtime.js +1 -1
- package/dist/src/agent/embedded/run-for-session.js +2 -2
- package/dist/src/agent/embedded/run-turn.js +5 -5
- package/dist/src/agent/external-tools/endpoint-provider.js +2 -2
- package/dist/src/agent/image/tool-model-config.js +1 -1
- package/dist/src/agent/inbound/attachment-pipeline.js +1 -1
- package/dist/src/agent/memory/compaction-promotion.d.ts +2 -0
- package/dist/src/agent/memory/compaction-promotion.js +33 -2
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service.js +7 -7
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/tasks/task-judge-service.js +3 -3
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/knowledge-memory-tool.js +14 -6
- package/dist/src/agent/tools/xopc-use-tool.js +2 -2
- package/dist/src/agent/workspace-runtime/registry.js +1 -1
- package/dist/src/agent-catalog/capabilities.js +2 -2
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/model-credential-store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +2 -2
- package/dist/src/automations/capabilities/drafts.js +1 -1
- package/dist/src/automations/draft/automation-draft-service.js +1 -1
- package/dist/src/automations/service/action-executor.js +1 -1
- package/dist/src/bootstrap/application-state.js +2 -2
- package/dist/src/capabilities/runtime/dispatcher.js +1 -1
- package/dist/src/capabilities/runtime/product.js +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -1
- package/dist/src/chat-commands/builtins/config.js +1 -1
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/agents.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/image-providers.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +2 -2
- package/dist/src/cli/commands/models.js +2 -2
- package/dist/src/cli/commands/onboard/model.js +4 -4
- package/dist/src/cli/extension-cli-register.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +1 -1
- package/dist/src/config/agent-model-intents.js +1 -1
- package/dist/src/config/agent-profile.js +2 -2
- package/dist/src/config/index.js +4 -4
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/schema.d.ts +5 -0
- package/dist/src/config/schema.js +5 -5
- package/dist/src/connectors/connected-source-ingestion.js +45 -7
- package/dist/src/connectors/connected-source-understanding.d.ts +1 -0
- package/dist/src/connectors/connected-source-understanding.js +59 -67
- package/dist/src/connectors/content-enrichment.js +1 -1
- package/dist/src/connectors/learning-coordinator.js +2 -2
- package/dist/src/extensions/activation-context.js +1 -1
- package/dist/src/extensions/agent-plugins/validation.js +1 -1
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/file-path-classifier.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -0
- package/dist/src/gateway/hono/lib/config-payload.js +2 -2
- package/dist/src/gateway/hono/routes/config-patch/misc.js +6 -6
- package/dist/src/gateway/hono/routes/connectors.js +1 -1
- package/dist/src/gateway/hono/routes/context-sources.js +2 -2
- package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -0
- package/dist/src/gateway/hono/routes/mcp.js +1 -1
- package/dist/src/gateway/hono/routes/memory-learning.d.ts +3 -0
- package/dist/src/gateway/hono/routes/memory-learning.js +76 -0
- package/dist/src/gateway/hono/routes/models.js +2 -2
- package/dist/src/gateway/hono/routes/notes.js +2 -2
- package/dist/src/gateway/hono/routes/observability.js +1 -1
- package/dist/src/gateway/hono/routes/projects.js +3 -3
- package/dist/src/gateway/hono/routes/session-input-handler.js +1 -1
- package/dist/src/gateway/hono/routes/tasks.js +1 -1
- package/dist/src/gateway/hono/routes/user-model-refresh.js +1 -1
- package/dist/src/gateway/hono/routes/user-model.js +5 -3
- package/dist/src/gateway/hono/routes/voice.js +1 -1
- package/dist/src/gateway/image-generation-setup.js +2 -2
- package/dist/src/gateway/lock.js +1 -1
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service.js +13 -13
- package/dist/src/gateway/xopc-cloud-capability-setup.js +1 -1
- package/dist/src/home-intelligence/generator.js +1 -1
- package/dist/src/home-intelligence/host.js +2 -2
- package/dist/src/imports/inventory.js +1 -1
- package/dist/src/knowledge/chunks.d.ts +10 -0
- package/dist/src/knowledge/chunks.js +28 -0
- package/dist/src/knowledge/connected-knowledge-pipeline.js +67 -33
- package/dist/src/knowledge/index.js +1 -1
- package/dist/src/knowledge/ingestion-service.js +5 -1
- package/dist/src/knowledge/local-folder-adapter.d.ts +2 -1
- package/dist/src/knowledge/local-folder-adapter.js +22 -13
- package/dist/src/knowledge-memory/domain.d.ts +4 -0
- package/dist/src/knowledge-memory/index.d.ts +1 -0
- package/dist/src/knowledge-memory/index.js +2 -1
- package/dist/src/knowledge-memory/repair-evidence.d.ts +2 -0
- package/dist/src/knowledge-memory/repair-evidence.js +57 -0
- package/dist/src/knowledge-memory/repository.d.ts +8 -0
- package/dist/src/knowledge-memory/repository.js +48 -27
- package/dist/src/knowledge-memory/search-text.d.ts +3 -0
- package/dist/src/knowledge-memory/search-text.js +32 -0
- package/dist/src/knowledge-memory/usage-policy.d.ts +6 -0
- package/dist/src/knowledge-memory/usage-policy.js +61 -0
- package/dist/src/local-apps/service.js +1 -1
- package/dist/src/memory-learning/repository.d.ts +24 -0
- package/dist/src/memory-learning/repository.js +96 -0
- package/dist/src/memory-learning/service.d.ts +17 -0
- package/dist/src/memory-learning/service.js +105 -0
- package/dist/src/memory-learning/source-learning.d.ts +7 -0
- package/dist/src/memory-learning/source-learning.js +235 -0
- package/dist/src/memory-learning/task-receipts.d.ts +3 -0
- package/dist/src/memory-learning/task-receipts.js +95 -0
- package/dist/src/memory-learning/work-capture.d.ts +51 -0
- package/dist/src/memory-learning/work-capture.js +140 -0
- package/dist/src/memory-maintenance/service.js +5 -5
- package/dist/src/notes/service.js +1 -1
- package/dist/src/observability/runtime.js +1 -1
- package/dist/src/personal-agent/proactivity/service.js +3 -3
- package/dist/src/personal-agent/prompt-context.js +4 -4
- package/dist/src/personal-agent/reply-composer.js +2 -2
- package/dist/src/personal-agent/service.js +2 -2
- package/dist/src/platform/index.js +1 -1
- package/dist/src/providers/index.js +4 -4
- package/dist/src/providers/local-model.d.ts +2 -0
- package/dist/src/providers/local-model.js +16 -0
- package/dist/src/providers/model-catalog-persistence.js +1 -1
- package/dist/src/providers/model-registry.js +2 -2
- package/dist/src/providers/provider-auth-service.js +1 -1
- package/dist/src/providers/provider-disconnect-core.js +1 -1
- package/dist/src/providers/register-runtime-providers.js +1 -1
- package/dist/src/providers/xopc-cloud-catalog-coordinator.js +1 -1
- package/dist/src/routing/resolve-route.js +1 -1
- package/dist/src/routing/resolve-tui-session-key.js +1 -1
- package/dist/src/scenes/taskFollowUp/service.js +1 -1
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/store.js +2 -1
- package/dist/src/storage/sqlite/knowledge-repository.js +6 -0
- package/dist/src/storage/sqlite/migrations/245_memory_learning.sql +125 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +6 -3
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tasks/capabilities/read.js +2 -2
- package/dist/src/tasks/task-handoff-service.js +1 -1
- package/dist/src/tasks/task-main-update-decision-service.js +1 -1
- package/dist/src/tui/backends/embedded-backend.js +5 -5
- package/dist/src/tui/extension-host/load-extensions.js +1 -1
- package/dist/src/tui/tui-commands.js +1 -1
- package/dist/src/tui/tui-skills-autocomplete.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +2 -2
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/user-context/access-policy.js +2 -1
- package/dist/src/user-context/config.d.ts +10 -0
- package/dist/src/user-context/config.js +5 -0
- package/dist/src/user-context/extraction/registry.d.ts +1 -1
- package/dist/src/user-context/extraction/registry.js +10 -0
- package/dist/src/user-context/identity-bindings.d.ts +10 -0
- package/dist/src/user-context/identity-bindings.js +24 -0
- package/dist/src/user-context/sources/consent-fields.d.ts +2 -0
- package/dist/src/user-context/sources/consent-fields.js +66 -0
- package/dist/src/user-model/bootstrap.js +1 -1
- package/dist/src/user-model/capture/executor.js +1 -1
- package/dist/src/user-model/capture/semantic.d.ts +3 -1
- package/dist/src/user-model/capture/semantic.js +14 -6
- package/dist/src/user-model/index.js +1 -1
- package/dist/src/user-model/usage-policy.js +34 -0
- package/dist/src/voice/platform-streams.js +1 -0
- package/dist/src/voice/realtime/memory-context.js +19 -5
- package/dist/src/voice/realtime/persona-context.js +1 -1
- package/dist/src/work-discovery/incremental-repository.js +1 -1
- package/dist/src/work-discovery/service.js +6 -6
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +38 -10
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/settings-advanced-gate-DpCanqrD.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-sx1lNWKf.js +0 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { inferMemorySensitivity } from "../agent/memory/sensitivity.js";
|
|
1
2
|
import { extname, relative, resolve, sep } from "node:path";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import { readFile, readdir, realpath, stat } from "node:fs/promises";
|
|
@@ -21,22 +22,19 @@ const MAX_FILES = 2e3;
|
|
|
21
22
|
const MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
22
23
|
var LocalFolderKnowledgeSourceAdapter = class {
|
|
23
24
|
kind = "local-folder";
|
|
24
|
-
constructor(rootPath) {
|
|
25
|
+
constructor(rootPath, pageSize = MAX_FILES) {
|
|
25
26
|
this.rootPath = rootPath;
|
|
27
|
+
this.pageSize = pageSize;
|
|
26
28
|
}
|
|
27
29
|
async pull(input) {
|
|
28
30
|
const scanStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
29
31
|
const root = await realpath(resolve(this.rootPath));
|
|
30
32
|
if (!(await stat(root)).isDirectory()) throw new Error(`Local knowledge source is not a directory: ${root}`);
|
|
31
|
-
const cursorMs = input.cursor ? Date.parse(input.cursor) : NaN;
|
|
32
|
-
const windowMs = input.windowStart ? Date.parse(input.windowStart) : NaN;
|
|
33
|
-
const changedAfter = Math.max(Number.isFinite(cursorMs) ? cursorMs : 0, Number.isFinite(windowMs) ? windowMs : 0);
|
|
34
33
|
const paths = [];
|
|
35
34
|
const warnings = [];
|
|
36
35
|
const walk = async (directory) => {
|
|
37
36
|
if (input.signal.aborted) throw input.signal.reason ?? /* @__PURE__ */ new Error("Local folder sync aborted.");
|
|
38
37
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
39
|
-
if (paths.length >= MAX_FILES) return;
|
|
40
38
|
if (entry.isSymbolicLink()) continue;
|
|
41
39
|
const path = resolve(directory, entry.name);
|
|
42
40
|
if (entry.isDirectory()) {
|
|
@@ -47,14 +45,24 @@ var LocalFolderKnowledgeSourceAdapter = class {
|
|
|
47
45
|
}
|
|
48
46
|
};
|
|
49
47
|
await walk(root);
|
|
50
|
-
|
|
48
|
+
paths.sort((left, right) => left.localeCompare(right));
|
|
49
|
+
let after;
|
|
50
|
+
try {
|
|
51
|
+
after = JSON.parse(input.cursor ?? "{}").after;
|
|
52
|
+
} catch {}
|
|
53
|
+
const remaining = after ? paths.filter((path) => relative(root, path).localeCompare(after) > 0) : paths;
|
|
54
|
+
const page = remaining.slice(0, this.pageSize);
|
|
55
|
+
const hasMore = remaining.length > page.length;
|
|
51
56
|
const items = [];
|
|
52
|
-
for (const path of
|
|
57
|
+
for (const path of page) {
|
|
53
58
|
if (input.signal.aborted) throw input.signal.reason ?? /* @__PURE__ */ new Error("Local folder sync aborted.");
|
|
54
59
|
const fileStat = await stat(path);
|
|
55
|
-
if (fileStat.size > MAX_FILE_BYTES || fileStat.mtimeMs <= changedAfter) continue;
|
|
56
60
|
const canonicalPath = await realpath(path);
|
|
57
61
|
if (canonicalPath !== root && !canonicalPath.startsWith(`${root}${sep}`)) continue;
|
|
62
|
+
if (fileStat.size > MAX_FILE_BYTES) {
|
|
63
|
+
warnings.push(`File exceeds ${MAX_FILE_BYTES} bytes and was excluded: ${relative(root, canonicalPath)}`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
58
66
|
const normalizedText = await readFile(canonicalPath, "utf8");
|
|
59
67
|
const externalId = relative(root, canonicalPath).split(sep).join("/");
|
|
60
68
|
items.push({
|
|
@@ -62,7 +70,7 @@ var LocalFolderKnowledgeSourceAdapter = class {
|
|
|
62
70
|
collectionScope: "files",
|
|
63
71
|
externalId,
|
|
64
72
|
itemType: "local_file",
|
|
65
|
-
authorRole: "
|
|
73
|
+
authorRole: "unknown",
|
|
66
74
|
sourceUpdatedAt: fileStat.mtime.toISOString(),
|
|
67
75
|
contentHash: createHash("sha256").update(normalizedText).digest("hex"),
|
|
68
76
|
normalizedText,
|
|
@@ -70,16 +78,17 @@ var LocalFolderKnowledgeSourceAdapter = class {
|
|
|
70
78
|
path: externalId,
|
|
71
79
|
rootPath: root
|
|
72
80
|
},
|
|
73
|
-
sensitivity:
|
|
74
|
-
retentionClass: "
|
|
81
|
+
sensitivity: inferMemorySensitivity(normalizedText),
|
|
82
|
+
retentionClass: "bounded",
|
|
75
83
|
synthesisPipeline: "connected_knowledge"
|
|
76
84
|
});
|
|
77
85
|
}
|
|
78
86
|
return {
|
|
79
87
|
items,
|
|
80
|
-
nextCursor: scanStartedAt,
|
|
88
|
+
nextCursor: hasMore ? JSON.stringify({ after: relative(root, page.at(-1)).split(sep).join("/") }) : scanStartedAt,
|
|
89
|
+
hasMore,
|
|
81
90
|
warnings,
|
|
82
|
-
snapshotExternalIds:
|
|
91
|
+
snapshotExternalIds: warnings.length ? void 0 : paths.map((path) => relative(root, path).split(sep).join("/"))
|
|
83
92
|
};
|
|
84
93
|
}
|
|
85
94
|
};
|
|
@@ -12,6 +12,10 @@ export interface KnowledgeReadPolicy {
|
|
|
12
12
|
contentSources: readonly KnowledgeContentSource[];
|
|
13
13
|
}
|
|
14
14
|
export interface KnowledgeItem {
|
|
15
|
+
retrievalSnippet?: string;
|
|
16
|
+
claimMode?: 'explicit' | 'observed' | 'inferred' | 'reported';
|
|
17
|
+
verification?: 'supported' | 'tentative' | 'conflicted';
|
|
18
|
+
sensitivity?: 'normal' | 'personal' | 'secret' | 'regulated';
|
|
15
19
|
id: string;
|
|
16
20
|
principalId: string;
|
|
17
21
|
kind: KnowledgeKind;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import { canUseKnowledge, knowledgeContentSources, knowledgeExclusion } from "./usage-policy.js";
|
|
1
2
|
import { KnowledgeReviewConflictError, classifyKnowledgeContentSource, deleteKnowledgeItem, getKnowledgeItem, isKnowledgeCurrent, knowledgeItemAllowed, listKnowledgeItems, listKnowledgeStatusEvents, reviewKnowledgeItem, searchKnowledgeItems, transitionKnowledgeStatus, writeKnowledgeItem } from "./repository.js";
|
|
2
|
-
export { KnowledgeReviewConflictError, classifyKnowledgeContentSource, deleteKnowledgeItem, getKnowledgeItem, isKnowledgeCurrent, knowledgeItemAllowed, listKnowledgeItems, listKnowledgeStatusEvents, reviewKnowledgeItem, searchKnowledgeItems, transitionKnowledgeStatus, writeKnowledgeItem };
|
|
3
|
+
export { KnowledgeReviewConflictError, canUseKnowledge, classifyKnowledgeContentSource, deleteKnowledgeItem, getKnowledgeItem, isKnowledgeCurrent, knowledgeContentSources, knowledgeExclusion, knowledgeItemAllowed, listKnowledgeItems, listKnowledgeStatusEvents, reviewKnowledgeItem, searchKnowledgeItems, transitionKnowledgeStatus, writeKnowledgeItem };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createContextEvidence, init_context_evidence_repository } from "../storage/sqlite/context-evidence-repository.js";
|
|
2
|
+
import { getKnowledgeSourceItem, init_knowledge_repository } from "../storage/sqlite/knowledge-repository.js";
|
|
3
|
+
import { getActiveUnderstandingConsent } from "../user-context/sources/consent-repository.js";
|
|
4
|
+
import { getUnderstandingSourceRun } from "../user-context/sources/repository.js";
|
|
5
|
+
import { listKnowledgeItems, writeKnowledgeItem } from "./repository.js";
|
|
6
|
+
//#region src/knowledge-memory/repair-evidence.ts
|
|
7
|
+
init_context_evidence_repository();
|
|
8
|
+
init_knowledge_repository();
|
|
9
|
+
/** Legacy summaries are usable only when their original retained source can still be verified. */
|
|
10
|
+
function repairLegacyKnowledgeEvidence() {
|
|
11
|
+
let repaired = 0;
|
|
12
|
+
for (const item of listKnowledgeItems({
|
|
13
|
+
recordClass: "memory",
|
|
14
|
+
statuses: ["candidate"],
|
|
15
|
+
limit: 1e3
|
|
16
|
+
})) {
|
|
17
|
+
if (item.originClass !== "untrusted" || item.verification !== "tentative" || typeof item.source.sourceRunId !== "string" || !Array.isArray(item.source.evidenceRefs)) continue;
|
|
18
|
+
const run = getUnderstandingSourceRun(item.source.sourceRunId);
|
|
19
|
+
const consent = run ? getActiveUnderstandingConsent(run.grantId) : void 0;
|
|
20
|
+
if (!consent || !consent.purposes.includes("work_assistance")) continue;
|
|
21
|
+
const sources = item.source.evidenceRefs.filter((ref) => typeof ref === "string").map((ref) => ref.startsWith("knowledge-source://") ? getKnowledgeSourceItem(ref.slice(19)) : void 0);
|
|
22
|
+
if (!sources.length || sources.some((source) => !source || source.deletedAt || Date.parse(source.updatedAt) > item.updatedAt)) continue;
|
|
23
|
+
const evidence = sources.map((source) => {
|
|
24
|
+
return {
|
|
25
|
+
id: createContextEvidence({
|
|
26
|
+
sourceType: "connector",
|
|
27
|
+
sourceInstanceId: source.sourceInstanceId,
|
|
28
|
+
sourceRef: `knowledge-source://${source.id}`,
|
|
29
|
+
sourceItemId: source.id,
|
|
30
|
+
contentHash: source.contentHash,
|
|
31
|
+
trustLevel: "untrusted",
|
|
32
|
+
observedAt: Date.parse(source.updatedAt),
|
|
33
|
+
processingPolicy: consent.processingPolicy
|
|
34
|
+
}).id,
|
|
35
|
+
contentHash: source.contentHash,
|
|
36
|
+
consentReceiptId: consent.id
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
writeKnowledgeItem({
|
|
40
|
+
...item,
|
|
41
|
+
claimMode: "reported",
|
|
42
|
+
verification: "supported",
|
|
43
|
+
status: item.confidence >= .7 ? "active" : "candidate",
|
|
44
|
+
evidence,
|
|
45
|
+
replaceExisting: true,
|
|
46
|
+
source: {
|
|
47
|
+
...item.source,
|
|
48
|
+
consentReceiptId: consent.id,
|
|
49
|
+
sourceInstanceId: sources[0].sourceInstanceId
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
repaired += 1;
|
|
53
|
+
}
|
|
54
|
+
return repaired;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { repairLegacyKnowledgeEvidence };
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { type UserModelScope } from '../user-model/domain.js';
|
|
2
2
|
import type { KnowledgeItem, KnowledgeKind, KnowledgeOriginClass, KnowledgeRecordClass, KnowledgeContentSource, KnowledgeReadPolicy, KnowledgeStatus, KnowledgeReviewAction, KnowledgeStatusActor, KnowledgeStatusEvent, KnowledgeVisibilityContext } from './domain.js';
|
|
3
3
|
export interface WriteKnowledgeInput {
|
|
4
|
+
claimMode?: KnowledgeItem['claimMode'];
|
|
5
|
+
verification?: KnowledgeItem['verification'];
|
|
6
|
+
sensitivity?: KnowledgeItem['sensitivity'];
|
|
7
|
+
evidence?: Array<{
|
|
8
|
+
id: string;
|
|
9
|
+
contentHash?: string;
|
|
10
|
+
consentReceiptId?: string;
|
|
11
|
+
}>;
|
|
4
12
|
principalId?: string;
|
|
5
13
|
kind: KnowledgeKind;
|
|
6
14
|
scope: UserModelScope;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { init_search_text, memorySearchQuery } from "./search-text.js";
|
|
1
2
|
import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
3
|
import { init_domain, validateScope } from "../user-model/domain.js";
|
|
3
|
-
import {
|
|
4
|
+
import { inferMemorySensitivity } from "../agent/memory/sensitivity.js";
|
|
4
5
|
import { clearMemoryAudit, isMemorySuppressed, memoryFingerprint, restoreMemory, suppressMemory } from "../user-context/memory-suppression.js";
|
|
6
|
+
import { canUseKnowledge, knowledgeContentSources } from "./usage-policy.js";
|
|
5
7
|
import { randomUUID } from "node:crypto";
|
|
6
8
|
//#region src/knowledge-memory/repository.ts
|
|
7
|
-
|
|
9
|
+
init_search_text();
|
|
8
10
|
init_transaction();
|
|
9
11
|
init_domain();
|
|
10
12
|
var KnowledgeReviewConflictError = class extends Error {
|
|
@@ -16,6 +18,9 @@ var KnowledgeReviewConflictError = class extends Error {
|
|
|
16
18
|
function fromRow(row) {
|
|
17
19
|
return {
|
|
18
20
|
id: row.knowledge_id,
|
|
21
|
+
claimMode: row.claim_mode,
|
|
22
|
+
verification: row.verification,
|
|
23
|
+
sensitivity: row.sensitivity,
|
|
19
24
|
principalId: row.principal_id,
|
|
20
25
|
kind: row.kind,
|
|
21
26
|
scope: {
|
|
@@ -62,7 +67,8 @@ function writeKnowledgeItem(input) {
|
|
|
62
67
|
if (input.validFrom !== void 0 && input.validTo !== void 0 && input.validTo < input.validFrom) throw new Error("Knowledge validTo must be greater than or equal to validFrom.");
|
|
63
68
|
const principalId = input.principalId ?? "local-owner";
|
|
64
69
|
const now = input.now ?? Date.now();
|
|
65
|
-
const
|
|
70
|
+
const supportedExternal = input.originClass === "untrusted" && input.verification === "supported" && Boolean(input.evidence?.length) && input.confidence >= .7;
|
|
71
|
+
const admittedStatus = input.status ?? (supportedExternal || input.originClass === "owner" || input.originClass !== "untrusted" && input.confidence >= .7 && !input.derivedFromRecalledContext ? "active" : "candidate");
|
|
66
72
|
return runSqliteWriteTransaction((db) => {
|
|
67
73
|
const keys = knowledgeFingerprints(input);
|
|
68
74
|
if (input.restoreDeleted && input.originClass === "owner") restoreMemory(db, keys);
|
|
@@ -90,13 +96,12 @@ function writeKnowledgeItem(input) {
|
|
|
90
96
|
created: false
|
|
91
97
|
};
|
|
92
98
|
if (existing) {
|
|
99
|
+
db.prepare("INSERT INTO knowledge_revisions(revision_id, knowledge_id, content, source_json, created_at) VALUES (?, ?, ?, ?, ?)").run(randomUUID(), existing.knowledge_id, existing.content, existing.source_json, now);
|
|
93
100
|
const nextStatus = admittedStatus;
|
|
94
101
|
db.prepare(`UPDATE knowledge_items SET kind = ?, content = ?, record_class = ?, status = ?, confidence = ?,
|
|
95
102
|
importance = ?, valid_from = ?, valid_to = ?, expires_at = ?, review_at = ?,
|
|
96
103
|
origin_class = ?, source_agent_id = ?, source_conversation_id = ?, source_turn_id = ?,
|
|
97
104
|
derived_from_recalled_context = ?, source_json = ?, updated_at = ? WHERE knowledge_id = ?`).run(input.kind, input.content.trim(), input.recordClass ?? "memory", nextStatus, input.confidence, input.importance, input.validFrom ?? null, input.validTo ?? null, input.expiresAt ?? null, input.reviewAt ?? null, input.originClass, input.sourceAgentId ?? null, input.sourceConversationId ?? null, input.sourceTurnId ?? null, input.derivedFromRecalledContext ? 1 : 0, JSON.stringify(input.source ?? {}), now, existing.knowledge_id);
|
|
98
|
-
db.prepare("DELETE FROM knowledge_items_fts WHERE knowledge_id = ?").run(existing.knowledge_id);
|
|
99
|
-
db.prepare("INSERT INTO knowledge_items_fts(content, knowledge_id) VALUES (?, ?)").run(input.content.trim(), existing.knowledge_id);
|
|
100
105
|
if (existing.status !== nextStatus) insertStatusEvent(db, {
|
|
101
106
|
knowledgeId: existing.knowledge_id,
|
|
102
107
|
fromStatus: existing.status,
|
|
@@ -105,6 +110,7 @@ function writeKnowledgeItem(input) {
|
|
|
105
110
|
reason: "Knowledge replaced from its source.",
|
|
106
111
|
now
|
|
107
112
|
});
|
|
113
|
+
writeEvidence(db, existing.knowledge_id, input);
|
|
108
114
|
return {
|
|
109
115
|
item: fromRow(db.prepare("SELECT * FROM knowledge_items WHERE knowledge_id = ?").get(existing.knowledge_id)),
|
|
110
116
|
created: false
|
|
@@ -118,7 +124,6 @@ function writeKnowledgeItem(input) {
|
|
|
118
124
|
origin_class, source_agent_id, source_conversation_id, source_turn_id,
|
|
119
125
|
derived_from_recalled_context, source_json, created_at, updated_at
|
|
120
126
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, principalId, input.kind, input.scope.type, input.scope.id ?? null, input.content.trim(), input.canonicalKey.trim(), input.recordClass ?? "memory", status, input.confidence, input.importance, input.validFrom ?? null, input.validTo ?? null, input.expiresAt ?? null, input.reviewAt ?? null, input.originClass, input.sourceAgentId ?? null, input.sourceConversationId ?? null, input.sourceTurnId ?? null, input.derivedFromRecalledContext ? 1 : 0, JSON.stringify(input.source ?? {}), now, now);
|
|
121
|
-
db.prepare("INSERT INTO knowledge_items_fts(content, knowledge_id) VALUES (?, ?)").run(input.content.trim(), id);
|
|
122
127
|
insertStatusEvent(db, {
|
|
123
128
|
knowledgeId: id,
|
|
124
129
|
fromStatus: null,
|
|
@@ -127,6 +132,7 @@ function writeKnowledgeItem(input) {
|
|
|
127
132
|
reason: "Knowledge admitted.",
|
|
128
133
|
now
|
|
129
134
|
});
|
|
135
|
+
writeEvidence(db, id, input);
|
|
130
136
|
return {
|
|
131
137
|
item: fromRow(db.prepare("SELECT * FROM knowledge_items WHERE knowledge_id = ?").get(id)),
|
|
132
138
|
created: true
|
|
@@ -166,9 +172,11 @@ function transitionKnowledgeStatus(input) {
|
|
|
166
172
|
db.prepare(`UPDATE knowledge_items SET status = ?, content = COALESCE(?, content),
|
|
167
173
|
origin_class = CASE WHEN ? THEN 'owner' ELSE origin_class END, updated_at = ?
|
|
168
174
|
WHERE knowledge_id = ?`).run(input.status, content ?? null, input.actor === "user" && input.status === "active" ? 1 : 0, now, input.id);
|
|
175
|
+
if (input.actor === "user" && input.status === "active") db.prepare("UPDATE knowledge_items SET claim_mode = 'explicit', verification = 'supported' WHERE knowledge_id = ?").run(input.id);
|
|
169
176
|
if (content !== void 0) {
|
|
170
|
-
db.prepare("
|
|
171
|
-
db.prepare("
|
|
177
|
+
db.prepare("INSERT INTO knowledge_revisions(revision_id, knowledge_id, content, source_json, created_at) VALUES (?, ?, ?, ?, ?)").run(randomUUID(), input.id, current.content, current.source_json, now);
|
|
178
|
+
db.prepare("DELETE FROM knowledge_evidence_links WHERE knowledge_id = ?").run(input.id);
|
|
179
|
+
db.prepare("UPDATE knowledge_items SET claim_mode = 'explicit', verification = 'supported', source_json = '{}' WHERE knowledge_id = ?").run(input.id);
|
|
172
180
|
}
|
|
173
181
|
if (input.actor === "user" && (input.status === "rejected" || input.status === "archived")) suppressMemory(db, knowledgeFingerprints(fromRow(current)), now);
|
|
174
182
|
insertStatusEvent(db, {
|
|
@@ -280,43 +288,51 @@ function visibilityClause(context, policy) {
|
|
|
280
288
|
values
|
|
281
289
|
};
|
|
282
290
|
}
|
|
283
|
-
function contentSourceClause(policy) {
|
|
284
|
-
if (!policy) return "1";
|
|
285
|
-
const allowed = new Set(policy.contentSources);
|
|
286
|
-
const importedSource = "COALESCE(json_extract(k.source_json, '$.kind'), '') = 'product_import'";
|
|
287
|
-
const parts = [];
|
|
288
|
-
if (allowed.has("memory")) parts.push("k.record_class = 'memory'");
|
|
289
|
-
if (allowed.has("local_import")) parts.push(`(k.record_class = 'source_index' AND ${importedSource})`);
|
|
290
|
-
if (allowed.has("connector")) parts.push(`(k.record_class = 'source_index' AND NOT (${importedSource}))`);
|
|
291
|
-
return `(${parts.length ? parts.join(" OR ") : "0"})`;
|
|
292
|
-
}
|
|
293
291
|
function searchKnowledgeItems(input) {
|
|
294
292
|
const principalId = input.principalId ?? "local-owner";
|
|
295
293
|
const asOf = input.asOf ?? Date.now();
|
|
296
294
|
const limit = Math.max(1, Math.min(100, input.limit ?? 12));
|
|
297
295
|
const visible = visibilityClause(input.context, input.policy);
|
|
298
|
-
const
|
|
299
|
-
const fts = buildFts5SearchQuery(input.query);
|
|
296
|
+
const fts = memorySearchQuery(input.query);
|
|
300
297
|
if (!fts) return [];
|
|
301
|
-
|
|
302
|
-
FROM
|
|
303
|
-
WHERE
|
|
298
|
+
const selected = getSqliteDatabase().prepare(`SELECT k.*, bm25(knowledge_search_fts) AS rank
|
|
299
|
+
FROM knowledge_search_fts JOIN knowledge_items k ON k.knowledge_id = knowledge_search_fts.knowledge_id
|
|
300
|
+
WHERE knowledge_search_fts MATCH ? AND k.principal_id = ? AND k.status = 'active'
|
|
304
301
|
AND (k.valid_from IS NULL OR k.valid_from <= ?)
|
|
305
302
|
AND (k.valid_to IS NULL OR k.valid_to >= ?)
|
|
306
303
|
AND (k.expires_at IS NULL OR k.expires_at >= ?)
|
|
307
304
|
AND (k.review_at IS NULL OR k.review_at > ?)
|
|
308
305
|
${input.recordClass ? "AND k.record_class = ?" : ""}
|
|
309
306
|
${input.trustedOnly ? "AND k.origin_class != 'untrusted'" : ""}
|
|
310
|
-
AND ${contentSource}
|
|
311
307
|
AND ${visible.sql}
|
|
312
|
-
ORDER BY rank ASC, k.importance DESC, k.updated_at DESC LIMIT ?`).all(fts, principalId, asOf, asOf, asOf, asOf, ...input.recordClass ? [input.recordClass] : [], ...visible.values, limit).map(fromRow);
|
|
308
|
+
ORDER BY rank ASC, k.importance DESC, k.updated_at DESC LIMIT ?`).all(fts, principalId, asOf, asOf, asOf, asOf, ...input.recordClass ? [input.recordClass] : [], ...visible.values, Math.min(1e3, limit * 10)).map(fromRow).filter((item) => canUseKnowledge(item, input.context, input.policy, asOf));
|
|
309
|
+
const chunks = getSqliteDatabase().prepare(`SELECT k.*, c.text AS chunk_text
|
|
310
|
+
FROM knowledge_chunks_fts f JOIN knowledge_source_chunks c ON c.chunk_id = f.chunk_id
|
|
311
|
+
JOIN knowledge_source_items s ON s.item_id = c.source_item_id AND s.content_hash = c.source_version
|
|
312
|
+
JOIN knowledge_items k ON json_extract(k.source_json, '$.sourceItemId') = s.item_id
|
|
313
|
+
WHERE knowledge_chunks_fts MATCH ? AND s.deleted_at IS NULL AND k.principal_id = ?
|
|
314
|
+
AND c.consent_receipt_id = json_extract(k.source_json, '$.consentReceiptId')
|
|
315
|
+
${input.recordClass ? "AND k.record_class = ?" : ""} AND ${visible.sql}
|
|
316
|
+
ORDER BY bm25(knowledge_chunks_fts) LIMIT ?`).all(fts, principalId, ...input.recordClass ? [input.recordClass] : [], ...visible.values, Math.min(1e3, limit * 10));
|
|
317
|
+
const seen = new Set(selected.map((item) => item.id));
|
|
318
|
+
for (const row of chunks) {
|
|
319
|
+
const item = fromRow(row);
|
|
320
|
+
if (!seen.has(item.id) && (!input.trustedOnly || item.originClass !== "untrusted") && canUseKnowledge(item, input.context, input.policy, asOf)) {
|
|
321
|
+
selected.push({
|
|
322
|
+
...item,
|
|
323
|
+
retrievalSnippet: row.chunk_text
|
|
324
|
+
});
|
|
325
|
+
seen.add(item.id);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return selected.slice(0, limit);
|
|
313
329
|
}
|
|
314
330
|
function classifyKnowledgeContentSource(item) {
|
|
315
331
|
if (item.recordClass === "memory") return "memory";
|
|
316
332
|
return item.source.kind === "product_import" ? "local_import" : "connector";
|
|
317
333
|
}
|
|
318
334
|
function knowledgeItemAllowed(item, policy) {
|
|
319
|
-
return policy.scopes.includes(item.scope.type) && policy.contentSources.includes(
|
|
335
|
+
return policy.scopes.includes(item.scope.type) && knowledgeContentSources(item).every((source) => policy.contentSources.includes(source));
|
|
320
336
|
}
|
|
321
337
|
function knowledgeFingerprints(input) {
|
|
322
338
|
const principal = input.principalId ?? "local-owner";
|
|
@@ -347,7 +363,7 @@ function deleteKnowledgeItem(id, now = Date.now()) {
|
|
|
347
363
|
const item = fromRow(row);
|
|
348
364
|
suppressMemory(db, knowledgeFingerprints(item), now);
|
|
349
365
|
clearMemoryAudit(db, "knowledge", item.id);
|
|
350
|
-
db.prepare("DELETE FROM
|
|
366
|
+
if (item.recordClass === "source_index" && typeof item.source.sourceItemId === "string") db.prepare("DELETE FROM knowledge_source_chunks WHERE source_item_id = ?").run(item.source.sourceItemId);
|
|
351
367
|
db.prepare("DELETE FROM knowledge_items WHERE knowledge_id = ?").run(item.id);
|
|
352
368
|
}
|
|
353
369
|
return rows.length > 0;
|
|
@@ -356,5 +372,10 @@ function deleteKnowledgeItem(id, now = Date.now()) {
|
|
|
356
372
|
function isKnowledgeCurrent(item, asOf = Date.now()) {
|
|
357
373
|
return item.status === "active" && (item.validFrom === void 0 || item.validFrom <= asOf) && (item.validTo === void 0 || item.validTo >= asOf) && (item.expiresAt === void 0 || item.expiresAt >= asOf) && (item.reviewAt === void 0 || item.reviewAt > asOf);
|
|
358
374
|
}
|
|
375
|
+
function writeEvidence(db, id, input) {
|
|
376
|
+
db.prepare("UPDATE knowledge_items SET claim_mode = ?, verification = ?, sensitivity = ? WHERE knowledge_id = ?").run(input.claimMode ?? (input.originClass === "owner" ? "explicit" : input.originClass === "untrusted" ? "reported" : "observed"), input.verification ?? (input.originClass === "untrusted" && (input.recordClass ?? "memory") === "memory" ? "tentative" : "supported"), input.sensitivity ?? inferMemorySensitivity(input.content), id);
|
|
377
|
+
db.prepare("DELETE FROM knowledge_evidence_links WHERE knowledge_id = ?").run(id);
|
|
378
|
+
for (const evidence of input.evidence ?? []) db.prepare("INSERT INTO knowledge_evidence_links(knowledge_id, evidence_id, content_hash, consent_receipt_id) VALUES (?, ?, ?, ?)").run(id, evidence.id, evidence.contentHash ?? null, evidence.consentReceiptId ?? null);
|
|
379
|
+
}
|
|
359
380
|
//#endregion
|
|
360
381
|
export { KnowledgeReviewConflictError, classifyKnowledgeContentSource, deleteKnowledgeItem, getKnowledgeItem, isKnowledgeCurrent, knowledgeItemAllowed, listKnowledgeItems, listKnowledgeStatusEvents, reviewKnowledgeItem, searchKnowledgeItems, transitionKnowledgeStatus, writeKnowledgeItem };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
|
|
2
|
+
//#region src/knowledge-memory/search-text.ts
|
|
3
|
+
/** Preserve original words while indexing Chinese characters and adjacent pairs. */
|
|
4
|
+
function memorySearchText(value) {
|
|
5
|
+
const normalized = value.normalize("NFKC").toLowerCase();
|
|
6
|
+
const terms = /* @__PURE__ */ new Set();
|
|
7
|
+
for (const match of normalized.matchAll(HAN)) {
|
|
8
|
+
const chars = Array.from(match[0]);
|
|
9
|
+
for (let i = 0; i < chars.length; i += 1) {
|
|
10
|
+
terms.add(chars[i]);
|
|
11
|
+
if (chars[i + 1]) terms.add(chars[i] + chars[i + 1]);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return `${normalized}\n${[...terms].join(" ")}`;
|
|
15
|
+
}
|
|
16
|
+
function memorySearchQuery(value) {
|
|
17
|
+
const words = value.normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? [];
|
|
18
|
+
const terms = [];
|
|
19
|
+
for (const word of words) if (/^\p{Script=Han}+$/u.test(word)) {
|
|
20
|
+
const chars = Array.from(word);
|
|
21
|
+
if (chars.length === 1) terms.push(word);
|
|
22
|
+
else for (let i = 0; i < chars.length - 1; i += 1) terms.push(chars[i] + chars[i + 1]);
|
|
23
|
+
} else if (word.length > 1) terms.push(word);
|
|
24
|
+
return [...new Set(terms)].slice(0, 32).map((term) => `"${term.replaceAll("\"", "\"\"")}"`).join(" OR ");
|
|
25
|
+
}
|
|
26
|
+
var HAN;
|
|
27
|
+
var init_search_text = __esmMin((() => {
|
|
28
|
+
HAN = /\p{Script=Han}+/gu;
|
|
29
|
+
}));
|
|
30
|
+
//#endregion
|
|
31
|
+
init_search_text();
|
|
32
|
+
export { init_search_text, memorySearchQuery, memorySearchText };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { KnowledgeItem, KnowledgeReadPolicy, KnowledgeVisibilityContext } from './domain.js';
|
|
2
|
+
export type KnowledgeExclusion = 'principal' | 'scope' | 'source_not_allowed' | 'expired' | 'conflicted' | 'sensitive' | 'evidence_missing' | 'source_revoked' | 'source_changed' | 'agent_not_allowed';
|
|
3
|
+
export declare function knowledgeContentSources(item: KnowledgeItem): Array<'memory' | 'local_import' | 'connector'>;
|
|
4
|
+
/** Source reliability affects how knowledge is described, never execution authority. */
|
|
5
|
+
export declare function knowledgeExclusion(item: KnowledgeItem, context: KnowledgeVisibilityContext, policy?: KnowledgeReadPolicy, asOf?: number): KnowledgeExclusion | undefined;
|
|
6
|
+
export declare function canUseKnowledge(item: KnowledgeItem, context: KnowledgeVisibilityContext, policy?: KnowledgeReadPolicy, asOf?: number): boolean;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getSqliteDatabase, init_transaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
import { getSessionMetadata } from "../storage/sqlite/session-read-repository.js";
|
|
3
|
+
import { init_session_repository } from "../storage/sqlite/session-repository.js";
|
|
4
|
+
import { getUnderstandingConsent } from "../user-context/sources/consent-repository.js";
|
|
5
|
+
import { isOwnerIdentity } from "../user-context/identity-bindings.js";
|
|
6
|
+
//#region src/knowledge-memory/usage-policy.ts
|
|
7
|
+
init_transaction();
|
|
8
|
+
init_session_repository();
|
|
9
|
+
function knowledgeContentSources(item) {
|
|
10
|
+
if (item.source.kind === "product_import") return ["local_import"];
|
|
11
|
+
if (typeof item.source.sourceInstanceId === "string" && item.source.sourceInstanceId.startsWith("local-folder:")) return item.recordClass === "memory" ? ["memory", "local_import"] : ["local_import"];
|
|
12
|
+
if (item.recordClass === "source_index" || item.source.sourceInstanceId || item.source.sourceRunId || item.source.consentReceiptId) return item.recordClass === "memory" ? ["memory", "connector"] : ["connector"];
|
|
13
|
+
return ["memory"];
|
|
14
|
+
}
|
|
15
|
+
/** Source reliability affects how knowledge is described, never execution authority. */
|
|
16
|
+
function knowledgeExclusion(item, context, policy, asOf = Date.now()) {
|
|
17
|
+
if (item.principalId !== "local-owner") return "principal";
|
|
18
|
+
if (!(item.scope.type === "global" || item.scope.id === {
|
|
19
|
+
agent: context.agentId,
|
|
20
|
+
workspace: context.workspaceId,
|
|
21
|
+
project: context.projectId,
|
|
22
|
+
session: context.conversationId
|
|
23
|
+
}[item.scope.type]) || policy && !policy.scopes.includes(item.scope.type)) return "scope";
|
|
24
|
+
if (policy && !knowledgeContentSources(item).every((source) => policy.contentSources.includes(source))) return "source_not_allowed";
|
|
25
|
+
if (item.status !== "active" || item.validFrom !== void 0 && item.validFrom > asOf || item.validTo !== void 0 && item.validTo < asOf || item.expiresAt !== void 0 && item.expiresAt < asOf || item.reviewAt !== void 0 && item.reviewAt <= asOf) return "expired";
|
|
26
|
+
if (item.verification === "conflicted" || item.verification === "tentative") return "conflicted";
|
|
27
|
+
if (item.sensitivity === "secret" || item.sensitivity === "regulated") return "sensitive";
|
|
28
|
+
if (item.originClass !== "owner" && item.sourceConversationId) {
|
|
29
|
+
const session = getSessionMetadata(item.sourceConversationId);
|
|
30
|
+
if (!session?.routing || session.routing.peerKind !== "direct" || !isOwnerIdentity(session.routing)) return "source_revoked";
|
|
31
|
+
}
|
|
32
|
+
const db = getSqliteDatabase();
|
|
33
|
+
const links = db.prepare(`SELECT e.*, l.content_hash AS linked_hash, l.consent_receipt_id
|
|
34
|
+
FROM knowledge_evidence_links l JOIN context_evidence e ON e.evidence_id = l.evidence_id
|
|
35
|
+
WHERE l.knowledge_id = ?`).all(item.id);
|
|
36
|
+
if (item.originClass === "untrusted" && !links.length) return "evidence_missing";
|
|
37
|
+
for (const link of links) {
|
|
38
|
+
if (link.conversation_id) {
|
|
39
|
+
const session = getSessionMetadata(link.conversation_id);
|
|
40
|
+
if (!session?.routing || session.routing.peerKind !== "direct" || !isOwnerIdentity(session.routing)) return "source_revoked";
|
|
41
|
+
}
|
|
42
|
+
if (link.linked_hash && link.linked_hash !== link.content_hash) return "source_changed";
|
|
43
|
+
if (link.source_item_id) {
|
|
44
|
+
const source = db.prepare("SELECT content_hash, deleted_at FROM knowledge_source_items WHERE item_id = ?").get(link.source_item_id);
|
|
45
|
+
if (!source || source.deleted_at) return "source_revoked";
|
|
46
|
+
if (link.linked_hash && link.linked_hash !== source.content_hash) return "source_changed";
|
|
47
|
+
}
|
|
48
|
+
if (link.source_type === "connector") {
|
|
49
|
+
if (!link.consent_receipt_id) return "evidence_missing";
|
|
50
|
+
const consent = getUnderstandingConsent(link.consent_receipt_id);
|
|
51
|
+
if (!consent || consent.revokedAt !== void 0 || !consent.purposes.includes("work_assistance")) return "source_revoked";
|
|
52
|
+
if (db.prepare("SELECT status FROM understanding_source_grants WHERE grant_id = ?").get(consent.grantId)?.status !== "active") return "source_revoked";
|
|
53
|
+
if (consent.allowedAgentIds && !consent.allowedAgentIds.includes(context.agentId)) return "agent_not_allowed";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function canUseKnowledge(item, context, policy, asOf = Date.now()) {
|
|
58
|
+
return knowledgeExclusion(item, context, policy, asOf) === void 0;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { canUseKnowledge, knowledgeContentSources, knowledgeExclusion };
|
|
@@ -5,10 +5,10 @@ import { currentOperationId, init_operation_context } from "../infra/operation-c
|
|
|
5
5
|
import { afterSqliteCommit, init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
6
6
|
import { ExtensionCapabilityBindingsSchema, extensionCapabilityPermissions } from "../../packages/gateway-contract/src/extension-capabilities.js";
|
|
7
7
|
import { init_src } from "../../packages/gateway-contract/src/index.js";
|
|
8
|
-
import { CapabilityError } from "../capabilities/runtime/errors.js";
|
|
9
8
|
import { init_paths, resolveExtensionsDir } from "../config/paths.js";
|
|
10
9
|
import { slugifyProjectName } from "../projects/project-store.js";
|
|
11
10
|
import { LocalAppStore } from "./store.js";
|
|
11
|
+
import { CapabilityError } from "../capabilities/runtime/errors.js";
|
|
12
12
|
import { DomainOutboxDispatcher } from "../infra/domain-outbox-dispatcher.js";
|
|
13
13
|
import { validateLocalAppCapabilityContracts } from "./capabilities/contracts.js";
|
|
14
14
|
import { buildLocalAppFixGuidance } from "./fix-guidance.js";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
export interface LearningJob {
|
|
3
|
+
job_id: string;
|
|
4
|
+
conversation_id: string;
|
|
5
|
+
transcript_id: string;
|
|
6
|
+
through_seq: number;
|
|
7
|
+
policy_hash: string;
|
|
8
|
+
workspace_id: string;
|
|
9
|
+
lease_token: string;
|
|
10
|
+
attempts: number;
|
|
11
|
+
start_seq?: number | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function learningPolicyHash(config: Config): string;
|
|
14
|
+
/** Recover learning intent from authoritative rows, including notifications lost in a crash. */
|
|
15
|
+
export declare function enqueueConversationLearning(config: Config, conversationId: string, workspaceId: string, force?: boolean, now?: number): string | undefined;
|
|
16
|
+
export declare function claimLearningJob(now?: number): LearningJob | undefined;
|
|
17
|
+
export declare function renewLearningLease(job: LearningJob): boolean;
|
|
18
|
+
/** Apply model results and advance progress atomically under the current lease. */
|
|
19
|
+
export declare function finishLearningJob(job: LearningJob, apply: () => void, processedThrough?: number): boolean;
|
|
20
|
+
export declare function failLearningJob(job: LearningJob, errorCode: string, canceled?: boolean): void;
|
|
21
|
+
export declare function learningStatus(config?: Config): {
|
|
22
|
+
jobs: unknown[];
|
|
23
|
+
coverage: unknown[];
|
|
24
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
import { resolveUserContextSessionAccess } from "../user-context/access-policy.js";
|
|
3
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
+
//#region src/memory-learning/repository.ts
|
|
5
|
+
init_transaction();
|
|
6
|
+
function learningPolicyHash(config) {
|
|
7
|
+
const catalog = getSqliteDatabase().prepare("SELECT revision FROM agent_catalog_settings WHERE singleton_id = 1").get();
|
|
8
|
+
return createHash("sha256").update(JSON.stringify({
|
|
9
|
+
config,
|
|
10
|
+
catalog
|
|
11
|
+
})).digest("hex");
|
|
12
|
+
}
|
|
13
|
+
/** Recover learning intent from authoritative rows, including notifications lost in a crash. */
|
|
14
|
+
function enqueueConversationLearning(config, conversationId, workspaceId, force = false, now = Date.now()) {
|
|
15
|
+
const access = resolveUserContextSessionAccess(config, conversationId);
|
|
16
|
+
if ((!access.userModel || config.userContext.userModel.writePolicy === "deny") && (!access.knowledge || config.userContext.knowledgeMemory.writePolicy === "deny")) return;
|
|
17
|
+
const idleMs = config.userContext.knowledgeMemory.learning?.idleFlushMs ?? 6e4;
|
|
18
|
+
return runSqliteWriteTransaction((db) => {
|
|
19
|
+
const transcript = db.prepare("SELECT active_transcript_id FROM sessions WHERE conversation_id = ?").get(conversationId);
|
|
20
|
+
if (!transcript?.active_transcript_id) return;
|
|
21
|
+
const id = transcript.active_transcript_id;
|
|
22
|
+
const last = db.prepare(`SELECT MAX(seq) AS seq, MAX(created_at) AS last_at FROM transcript_entries
|
|
23
|
+
WHERE transcript_id = ? AND role = 'assistant'`).get(id);
|
|
24
|
+
if (!last.seq) return;
|
|
25
|
+
db.prepare(`INSERT OR IGNORE INTO memory_learning_cursors(conversation_id, transcript_id, updated_at) VALUES (?, ?, ?)`).run(conversationId, id, now);
|
|
26
|
+
const cursor = db.prepare("SELECT processed_seq FROM memory_learning_cursors WHERE conversation_id = ? AND transcript_id = ?").get(conversationId, id);
|
|
27
|
+
if (!force && cursor.processed_seq >= last.seq) return;
|
|
28
|
+
const count = db.prepare(`SELECT COUNT(*) AS n FROM transcript_entries WHERE transcript_id = ? AND seq > ? AND role = 'user'`).get(id, cursor.processed_seq);
|
|
29
|
+
const due = force || count.n >= config.userContext.userModel.extraction.reviewIntervalTurns || now - (last.last_at ?? now) >= idleMs;
|
|
30
|
+
const jobId = randomUUID();
|
|
31
|
+
const inserted = db.prepare(`INSERT OR IGNORE INTO memory_learning_jobs(job_id, conversation_id, transcript_id,
|
|
32
|
+
through_seq, start_seq, extractor_version, policy_hash, workspace_id, state, next_attempt_at, created_at, updated_at)
|
|
33
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'queued', ?, ?, ?)`).run(jobId, conversationId, id, last.seq, force ? 0 : null, force ? `rebuild:${jobId}` : `2:${cursor.processed_seq}`, learningPolicyHash(config), workspaceId, due ? now : (last.last_at ?? now) + idleMs, now, now);
|
|
34
|
+
db.prepare(`UPDATE memory_learning_cursors SET observed_seq = MAX(observed_seq, ?), updated_at = ?
|
|
35
|
+
WHERE conversation_id = ? AND transcript_id = ?`).run(last.seq, now, conversationId, id);
|
|
36
|
+
return inserted.changes ? jobId : void 0;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function claimLearningJob(now = Date.now()) {
|
|
40
|
+
return runSqliteWriteTransaction((db) => {
|
|
41
|
+
db.prepare("UPDATE memory_learning_jobs SET state = 'failed', error_code = 'lease_expired', updated_at = ? WHERE state = 'running' AND attempts >= 3 AND lease_until < ?").run(now, now);
|
|
42
|
+
const row = db.prepare(`SELECT * FROM memory_learning_jobs j WHERE
|
|
43
|
+
((state IN ('queued', 'retry_wait') AND next_attempt_at <= ?) OR (state = 'running' AND lease_until < ?))
|
|
44
|
+
AND NOT EXISTS (SELECT 1 FROM memory_learning_jobs other WHERE other.conversation_id = j.conversation_id
|
|
45
|
+
AND other.state = 'running' AND other.lease_until >= ? AND other.job_id != j.job_id)
|
|
46
|
+
AND attempts < 3 ORDER BY created_at LIMIT 1`).get(now, now, now);
|
|
47
|
+
if (!row) return;
|
|
48
|
+
const token = randomUUID();
|
|
49
|
+
db.prepare(`UPDATE memory_learning_jobs SET state = 'running', lease_token = ?, lease_until = ?,
|
|
50
|
+
attempts = attempts + 1, updated_at = ? WHERE job_id = ?`).run(token, now + 18e4, now, row.job_id);
|
|
51
|
+
return {
|
|
52
|
+
...row,
|
|
53
|
+
lease_token: token,
|
|
54
|
+
attempts: row.attempts + 1
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function renewLearningLease(job) {
|
|
59
|
+
return Boolean(getSqliteDatabase().prepare(`UPDATE memory_learning_jobs SET lease_until = ?
|
|
60
|
+
WHERE job_id = ? AND state = 'running' AND lease_token = ?`).run(Date.now() + 18e4, job.job_id, job.lease_token).changes);
|
|
61
|
+
}
|
|
62
|
+
/** Apply model results and advance progress atomically under the current lease. */
|
|
63
|
+
function finishLearningJob(job, apply, processedThrough = job.through_seq) {
|
|
64
|
+
return runSqliteWriteTransaction((db) => {
|
|
65
|
+
if (!db.prepare(`SELECT 1 FROM memory_learning_jobs WHERE job_id = ? AND state = 'running'
|
|
66
|
+
AND lease_token = ? AND lease_until >= ?`).get(job.job_id, job.lease_token, Date.now())) return false;
|
|
67
|
+
apply();
|
|
68
|
+
db.prepare(`UPDATE memory_learning_cursors SET processed_seq = MAX(processed_seq, ?), updated_at = ?
|
|
69
|
+
WHERE conversation_id = ? AND transcript_id = ?`).run(processedThrough, Date.now(), job.conversation_id, job.transcript_id);
|
|
70
|
+
db.prepare(`UPDATE memory_learning_jobs SET state = 'succeeded', lease_token = NULL, lease_until = NULL, updated_at = ? WHERE job_id = ?`).run(Date.now(), job.job_id);
|
|
71
|
+
db.prepare(`UPDATE memory_learning_jobs SET state = 'canceled', updated_at = ? WHERE conversation_id = ?
|
|
72
|
+
AND transcript_id = ? AND through_seq <= ? AND start_seq IS NULL AND state IN ('queued','retry_wait')`).run(Date.now(), job.conversation_id, job.transcript_id, processedThrough);
|
|
73
|
+
if (processedThrough < job.through_seq) {
|
|
74
|
+
const nextId = randomUUID();
|
|
75
|
+
db.prepare(`INSERT INTO memory_learning_jobs(job_id, conversation_id, transcript_id, through_seq,
|
|
76
|
+
start_seq, extractor_version, policy_hash, workspace_id, state, next_attempt_at, created_at, updated_at)
|
|
77
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'queued', ?, ?, ?)`).run(nextId, job.conversation_id, job.transcript_id, job.through_seq, job.start_seq == null ? null : processedThrough, job.start_seq == null ? `2:${processedThrough}` : `rebuild:${nextId}`, job.policy_hash, job.workspace_id, Date.now(), Date.now(), Date.now());
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function failLearningJob(job, errorCode, canceled = false) {
|
|
83
|
+
getSqliteDatabase().prepare(`UPDATE memory_learning_jobs SET state = ?, error_code = ?, lease_token = NULL,
|
|
84
|
+
lease_until = NULL, next_attempt_at = ?, updated_at = ? WHERE job_id = ? AND lease_token = ?`).run(canceled ? "canceled" : job.attempts >= 3 ? "failed" : "retry_wait", errorCode, Date.now() + 3e4 * 2 ** job.attempts, Date.now(), job.job_id, job.lease_token);
|
|
85
|
+
}
|
|
86
|
+
function learningStatus(config) {
|
|
87
|
+
const db = getSqliteDatabase();
|
|
88
|
+
return {
|
|
89
|
+
jobs: db.prepare(`SELECT state, error_code AS errorCode, COUNT(*) AS count FROM (
|
|
90
|
+
SELECT state, error_code, policy_hash FROM memory_learning_jobs UNION ALL SELECT state, error_code, policy_hash FROM memory_source_learning_jobs
|
|
91
|
+
) ${config ? "WHERE policy_hash = ?" : ""} GROUP BY state, error_code`).all(...config ? [learningPolicyHash(config)] : []),
|
|
92
|
+
coverage: db.prepare("SELECT record_class AS recordClass, status, verification, COUNT(*) AS count FROM knowledge_items GROUP BY record_class, status, verification").all()
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { claimLearningJob, enqueueConversationLearning, failLearningJob, finishLearningJob, learningPolicyHash, learningStatus, renewLearningLease };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
import { type LearningJob } from './repository.js';
|
|
3
|
+
export declare class MemoryLearningService {
|
|
4
|
+
private readonly options;
|
|
5
|
+
private timer?;
|
|
6
|
+
private running;
|
|
7
|
+
private stopped;
|
|
8
|
+
private lastRetentionSweep;
|
|
9
|
+
constructor(options: {
|
|
10
|
+
getConfig: () => Config | undefined;
|
|
11
|
+
workspaceForSession: (id: string) => string;
|
|
12
|
+
execute: (job: LearningJob) => Promise<void>;
|
|
13
|
+
});
|
|
14
|
+
start(): void;
|
|
15
|
+
stop(): void;
|
|
16
|
+
runNow(): Promise<void>;
|
|
17
|
+
}
|