@xopcai/xopc 0.0.159 → 0.0.161
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/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{action-boundary-settings-panel-CaRK2vIy.js → action-boundary-settings-panel-BIVBUiNT.js} +1 -1
- package/dist/gateway/static/root/assets/activity-store-o7GRljfD.js +1 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BeVf03hx.js → agent-avatar-dicebear-9R3szLMc.js} +1 -1
- package/dist/gateway/static/root/assets/agents-_qbUaYbs.js +2 -0
- package/dist/gateway/static/root/assets/{api-BjcBIV2O.js → api-jSTqFMq9.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BG2ulMYw.js → app-management-settings-panel-D81cyE76.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-0Kjenr2T.js → appearance-settings-Ct6bZQCV.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-0sPqD0FK.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-ChiNnH1e.js → archive-plugin-CfD7AZKn.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-pbBlQR-g.js → attachment-load-CP_Gaxt3.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-CTZDOyDy.js → automation-suggestion-card-BGKM_NDZ.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-BxWBuBsE.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BeZGzpGF.js → binary-plugins-IPr2EVnS.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BnDmhN5Z.js → block-editor-B6aHEGA6.js} +3 -3
- package/dist/gateway/static/root/assets/browser-settings-page-C499b9AH.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-Ii36j_7v.js → capability-presets-api-CCX9-LjU.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-Cl3dw4yh.js → capability-presets-settings-panel-Dva9SiPK.js} +2 -2
- package/dist/gateway/static/root/assets/{channel-recipient-api-CFqrSi5K.js → channel-recipient-api-MmLMLDWf.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-DNAU7u9o.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-CIOH7tgn.js +1 -0
- package/dist/gateway/static/root/assets/check-DUBLcKHA.js +1 -0
- package/dist/gateway/static/root/assets/circle-alert-BEjgurr2.js +1 -0
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-CiLxuZ8S.js → connector-logo-BbjzIs87.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-TwiBp8vY.js +2 -0
- package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-CYH5ZSXy.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-settings-DQLqGLc0.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-sprite-DTqXSpqf.js +1 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-CC2VL5Mc.js → directory-picker-path-field-ClsiXhmz.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-KY7ZfVsy.js → dreaming-settings-CjMPPdzg.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-C8KBeucs.js → extension-debug-page-57eizjhB.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CV-5Kcyk.js → extension-page-CsbSb3u1.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DvUtDrAu.js → extension-settings-page-DKA9-lyP.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-DXfVeJLc.js → gateway-config-api-DIPJuzBZ.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-CDLqAQY7.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-cxQ94qMm.js → gateway-startup-retry-DrfSJtvT.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-Q3B0E-0s.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-C5VAK04G.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-P8VhLqYF.js → goals-config-api-lGC10UkU.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-BJb-5IYw.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-DHXyaH_O.js → goals-settings-BWq0pdrA.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-CNckP_Dv.js → heartbeat-settings-D4o8BJVv.js} +1 -1
- package/dist/gateway/static/root/assets/index-CkUHH170.css +1 -0
- package/dist/gateway/static/root/assets/index-vq_cJZJC.js +199 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-jXmv1RVX.js → keyboard-shortcuts-settings-6T2QYehS.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-euH17Kvb.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-Cs5LKjtc.js → local-apps-page-DCjg2K9f.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-C_M71MK9.js → locale-store-Dar-xqQr.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CyYCBqym.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-BFqeSNte.js → markdown-split-rt1XO43g.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Cc8379gq.js → media-plugins-Bwo8CJuh.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CxySDn9d.js +5 -0
- package/dist/gateway/static/root/assets/models-hub-panel-DObxxjc9.js +2 -0
- package/dist/gateway/static/root/assets/{notes-page-DlGU4ipo.js → notes-page-Dp-pkX7d.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-CCb4RXcZ.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-kFOswGlG.js → page-tabs-CzZ4iKOb.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-CvjuvABg.js → preview-open-alternatives-3E_Qa-58.js} +1 -1
- package/dist/gateway/static/root/assets/product-delivery-BTRT9kCS.js +1 -0
- package/dist/gateway/static/root/assets/product-open-page-B2T48Sbt.js +1 -0
- package/dist/gateway/static/root/assets/project-detail-page-BvEcriRC.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-B_e79MRJ.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-DGcqnYfR.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-DwrD7ODx.js → save-bar-controls-CkeKasGm.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-Ba4WzTmE.js → schedule-field-TkqUL3wm.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-DvydL8eF.js → schema-form-DC-iU5IG.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DQZhrDJ8.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BkdeN99Y.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-LaQqGGej.js → settings-collapsible-section-Dpqth3oA.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DruI__qO.js → settings-form-section-CNqF6IwY.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-UvA-eDhF.js → settings-loading-skeleton-DkvwitK_.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-DG-XMIPu.js → settings-page-layout-DWvNgISx.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-5oCGSebm.js → settings-page-qPG7I2zd.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-lwRAh9aw.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-FLVeTrRt.js → share-preview-page-DGpSPW-n.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-BGj9IVUr.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-B2UBAs5U.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DdjzFZ8I.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-CeK93xVi.js → system-settings-panel-8TxxSbUw.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-C8ohIHhw.js → theme-store-B5FzMWOx.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-D1Lr2gG0.js → typed-models-lib-DEGtSA5h.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-BWzou5ar.js → use-channel-catalog-BDU6FneG.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-BTTZpAGV.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-DuDQd-WU.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-BUVkVCsW.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-DeEPPu4n.js +1 -0
- package/dist/gateway/static/root/assets/work-page-DQNUyTUq.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Bynqe4kV.js → workflow-run-setup-panel-Cwi8Pz7n.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-BIy4wrzO.js +11 -0
- package/dist/gateway/static/root/index.html +12 -10
- package/dist/package.js +1 -1
- package/dist/src/automations/service/action-executor.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/mapper.d.ts +1 -0
- package/dist/src/gateway/chat-stream/mapper.js +43 -7
- package/dist/src/gateway/hono/routes/home.js +15 -2
- package/dist/src/gateway/hono/routes/work-discovery.js +451 -0
- package/dist/src/gateway/hono/sse.d.ts +2 -0
- package/dist/src/gateway/hono/sse.js +10 -3
- package/dist/src/gateway/run-loop.js +17 -7
- package/dist/src/gateway/server.d.ts +1 -0
- package/dist/src/gateway/server.js +9 -0
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +27 -2
- package/dist/src/local-apps/preview-runtime-bridge.d.ts +1 -1
- package/dist/src/local-apps/preview-runtime-bridge.js +14 -11
- package/dist/src/mobile/notification-service.js +1 -0
- package/dist/src/pets/factory.js +23 -26
- package/dist/src/pets/manifest.d.ts +2 -1
- package/dist/src/pets/manifest.js +15 -8
- package/dist/src/pets/validator.js +8 -3
- package/dist/src/proactive/calendar-signals.d.ts +4 -0
- package/dist/src/proactive/calendar-signals.js +120 -0
- package/dist/src/proactive/focus-service.d.ts +62 -0
- package/dist/src/proactive/focus-service.js +173 -0
- package/dist/src/proactive/index.d.ts +7 -0
- package/dist/src/proactive/index.js +7 -0
- package/dist/src/proactive/insight-repository.d.ts +19 -0
- package/dist/src/proactive/insight-repository.js +106 -0
- package/dist/src/proactive/run-processor.d.ts +19 -0
- package/dist/src/proactive/run-processor.js +125 -0
- package/dist/src/proactive/trial-expiry-reconciler.d.ts +5 -0
- package/dist/src/proactive/trial-expiry-reconciler.js +30 -0
- package/dist/src/proactive/types.d.ts +64 -0
- package/dist/src/proactive/types.js +1 -0
- package/dist/src/proactive/watch-repository.d.ts +28 -0
- package/dist/src/proactive/watch-repository.js +129 -0
- package/dist/src/storage/sqlite/knowledge-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/knowledge-repository.js +4 -0
- package/dist/src/storage/sqlite/migrations/047_work_discovery_sources.sql +16 -0
- package/dist/src/storage/sqlite/migrations/048_work_understanding_investigations.sql +40 -0
- package/dist/src/storage/sqlite/migrations/049_work_understanding_threads.sql +52 -0
- package/dist/src/storage/sqlite/migrations/050_work_discovery_source_refreshes.sql +15 -0
- package/dist/src/storage/sqlite/migrations/051_focus_watches.sql +26 -0
- package/dist/src/storage/sqlite/migrations/052_proactive_insights.sql +25 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/work-discovery/analyzer.d.ts +12 -1
- package/dist/src/work-discovery/analyzer.js +126 -7
- package/dist/src/work-discovery/candidate-discovery.d.ts +17 -0
- package/dist/src/work-discovery/candidate-discovery.js +279 -0
- package/dist/src/work-discovery/evaluation.d.ts +11 -0
- package/dist/src/work-discovery/evaluation.js +17 -0
- package/dist/src/work-discovery/governance.d.ts +25 -0
- package/dist/src/work-discovery/governance.js +96 -0
- package/dist/src/work-discovery/incremental-repository.d.ts +13 -0
- package/dist/src/work-discovery/incremental-repository.js +55 -0
- package/dist/src/work-discovery/incremental.d.ts +2 -0
- package/dist/src/work-discovery/incremental.js +7 -0
- package/dist/src/work-discovery/index.d.ts +10 -0
- package/dist/src/work-discovery/index.js +13 -3
- package/dist/src/work-discovery/investigation-repository.d.ts +16 -0
- package/dist/src/work-discovery/investigation-repository.js +122 -0
- package/dist/src/work-discovery/investigator.d.ts +55 -0
- package/dist/src/work-discovery/investigator.js +358 -0
- package/dist/src/work-discovery/probe.d.ts +22 -0
- package/dist/src/work-discovery/probe.js +88 -1
- package/dist/src/work-discovery/service.d.ts +110 -1
- package/dist/src/work-discovery/service.js +578 -8
- package/dist/src/work-discovery/source-repository.d.ts +13 -0
- package/dist/src/work-discovery/source-repository.js +72 -0
- package/dist/src/work-discovery/thread-repository.d.ts +34 -0
- package/dist/src/work-discovery/thread-repository.js +112 -0
- package/dist/src/work-discovery/thread-service.d.ts +8 -0
- package/dist/src/work-discovery/thread-service.js +104 -0
- package/dist/src/work-discovery/types.d.ts +145 -0
- package/package.json +1 -1
- package/skills/creative/hatch-pet/SKILL.md +2 -2
- package/dist/gateway/static/root/assets/activity-store-C-57rvkX.js +0 -1
- package/dist/gateway/static/root/assets/agents-P05C4A-3.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-DANGrBpN.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-BXfGL_cm.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-534luV0B.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-M91zFJVi.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-vooEF4lG.js +0 -1
- package/dist/gateway/static/root/assets/check-BODqo66o.js +0 -1
- package/dist/gateway/static/root/assets/circle-alert-RzVebuX2.js +0 -1
- package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CV5UulW6.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-Cil2eSpW.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-DwsC6l5F.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-sprite-DqZ6fbIj.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-BpJ0v56l.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-lMHD-2CX.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-yPmF-G7b.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-BHTCKobG.js +0 -2
- package/dist/gateway/static/root/assets/index-BgZhEOkN.css +0 -1
- package/dist/gateway/static/root/assets/index-BuqGh2SW.js +0 -193
- package/dist/gateway/static/root/assets/local-app-workbench-page-zpp_wciE.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-B4CRYqYR.js +0 -7
- package/dist/gateway/static/root/assets/messages-BuT0SR1R.js +0 -5
- package/dist/gateway/static/root/assets/models-hub-panel-1hdoAoB_.js +0 -2
- package/dist/gateway/static/root/assets/notes-workbench-DQEAZTA5.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-Bp9bC7A6.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-RNorFXTw.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BqRTcM_6.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-B2EfW1cm.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CklL85T4.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-D3my1HgB.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DVxgjrsP.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-Bcu58ZaF.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CDd-84FE.js +0 -2
- package/dist/gateway/static/root/assets/sliding-segmented-uWmrxE3P.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-1OyJnTyR.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-B2ncRwHS.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-BZlY4PZL.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-DPXMrneY.js +0 -1
- package/dist/gateway/static/root/assets/work-page-CTERoqyv.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-CLgsnqFQ.js +0 -11
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { requireXopcDatabase } from "../storage/sqlite/connection.js";
|
|
2
|
+
import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
//#region src/work-discovery/investigation-repository.ts
|
|
5
|
+
function parseJson(value, fallback) {
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(value);
|
|
8
|
+
} catch {
|
|
9
|
+
return fallback;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function investigationFromRow(row) {
|
|
13
|
+
return {
|
|
14
|
+
id: row.investigation_id,
|
|
15
|
+
discoveryRunId: row.discovery_run_id,
|
|
16
|
+
status: row.status,
|
|
17
|
+
plan: parseJson(row.plan_json, {
|
|
18
|
+
hypotheses: [],
|
|
19
|
+
questions: []
|
|
20
|
+
}),
|
|
21
|
+
budget: parseJson(row.budget_json, {
|
|
22
|
+
maxToolCalls: 0,
|
|
23
|
+
maxContentChars: 0,
|
|
24
|
+
maxDurationMs: 0
|
|
25
|
+
}),
|
|
26
|
+
toolCallCount: row.tool_call_count,
|
|
27
|
+
contentCharsRead: row.content_chars_read,
|
|
28
|
+
startedAt: row.started_at,
|
|
29
|
+
...row.completed_at != null ? { completedAt: row.completed_at } : {},
|
|
30
|
+
...row.error_message ? { errorMessage: row.error_message } : {}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function evidenceFromRow(row) {
|
|
34
|
+
return {
|
|
35
|
+
id: row.evidence_id,
|
|
36
|
+
investigationId: row.investigation_id,
|
|
37
|
+
...row.source_grant_id ? { sourceGrantId: row.source_grant_id } : {},
|
|
38
|
+
...row.project_id ? { projectId: row.project_id } : {},
|
|
39
|
+
sourceType: row.source_type,
|
|
40
|
+
sourceRef: row.source_ref,
|
|
41
|
+
observation: row.observation,
|
|
42
|
+
...row.content_hash ? { contentHash: row.content_hash } : {},
|
|
43
|
+
...row.observed_at != null ? { observedAt: row.observed_at } : {},
|
|
44
|
+
collectedAt: row.collected_at,
|
|
45
|
+
sensitivity: row.sensitivity === "restricted" ? "restricted" : "normal"
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function createWorkUnderstandingInvestigation(input) {
|
|
49
|
+
const now = input.nowMs ?? Date.now();
|
|
50
|
+
const id = randomUUID();
|
|
51
|
+
runSqliteWriteTransaction((db) => {
|
|
52
|
+
db.prepare(`INSERT INTO work_understanding_investigations (
|
|
53
|
+
investigation_id, discovery_run_id, status, plan_json, budget_json,
|
|
54
|
+
tool_call_count, content_chars_read, started_at
|
|
55
|
+
) VALUES (?, ?, 'planning', ?, ?, 0, 0, ?)`).run(id, input.discoveryRunId, JSON.stringify({
|
|
56
|
+
hypotheses: [],
|
|
57
|
+
questions: []
|
|
58
|
+
}), JSON.stringify(input.budget), now);
|
|
59
|
+
});
|
|
60
|
+
return getWorkUnderstandingInvestigation(id);
|
|
61
|
+
}
|
|
62
|
+
function getWorkUnderstandingInvestigation(id) {
|
|
63
|
+
const { db } = requireXopcDatabase();
|
|
64
|
+
const row = db.prepare("SELECT * FROM work_understanding_investigations WHERE investigation_id = ?").get(id);
|
|
65
|
+
return row ? investigationFromRow(row) : null;
|
|
66
|
+
}
|
|
67
|
+
function getWorkUnderstandingInvestigationForRun(runId) {
|
|
68
|
+
const { db } = requireXopcDatabase();
|
|
69
|
+
const row = db.prepare("SELECT * FROM work_understanding_investigations WHERE discovery_run_id = ?").get(runId);
|
|
70
|
+
return row ? investigationFromRow(row) : null;
|
|
71
|
+
}
|
|
72
|
+
function updateWorkUnderstandingInvestigation(id, patch) {
|
|
73
|
+
const existing = getWorkUnderstandingInvestigation(id);
|
|
74
|
+
if (!existing) return null;
|
|
75
|
+
const next = {
|
|
76
|
+
...existing,
|
|
77
|
+
...patch
|
|
78
|
+
};
|
|
79
|
+
runSqliteWriteTransaction((db) => {
|
|
80
|
+
db.prepare(`UPDATE work_understanding_investigations SET
|
|
81
|
+
status = ?, plan_json = ?, tool_call_count = ?, content_chars_read = ?,
|
|
82
|
+
error_message = ?, completed_at = ? WHERE investigation_id = ?`).run(next.status, JSON.stringify(next.plan), next.toolCallCount, next.contentCharsRead, next.errorMessage ?? null, next.completedAt ?? null, id);
|
|
83
|
+
});
|
|
84
|
+
return getWorkUnderstandingInvestigation(id);
|
|
85
|
+
}
|
|
86
|
+
function resetWorkUnderstandingInvestigation(id, budget, nowMs = Date.now()) {
|
|
87
|
+
if (!getWorkUnderstandingInvestigation(id)) return null;
|
|
88
|
+
runSqliteWriteTransaction((db) => {
|
|
89
|
+
db.prepare("DELETE FROM work_understanding_evidence WHERE investigation_id = ?").run(id);
|
|
90
|
+
db.prepare(`UPDATE work_understanding_investigations SET
|
|
91
|
+
status = 'planning', plan_json = ?, budget_json = ?, tool_call_count = 0,
|
|
92
|
+
content_chars_read = 0, error_message = NULL, started_at = ?, completed_at = NULL
|
|
93
|
+
WHERE investigation_id = ?`).run(JSON.stringify({
|
|
94
|
+
hypotheses: [],
|
|
95
|
+
questions: []
|
|
96
|
+
}), JSON.stringify(budget), nowMs, id);
|
|
97
|
+
});
|
|
98
|
+
return getWorkUnderstandingInvestigation(id);
|
|
99
|
+
}
|
|
100
|
+
function appendWorkUnderstandingEvidence(input) {
|
|
101
|
+
const id = input.id ?? randomUUID();
|
|
102
|
+
const collectedAt = input.collectedAt ?? Date.now();
|
|
103
|
+
runSqliteWriteTransaction((db) => {
|
|
104
|
+
db.prepare(`INSERT INTO work_understanding_evidence (
|
|
105
|
+
evidence_id, investigation_id, source_grant_id, project_id, source_type,
|
|
106
|
+
source_ref, observation, content_hash, observed_at, collected_at, sensitivity
|
|
107
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.investigationId, input.sourceGrantId ?? null, input.projectId ?? null, input.sourceType, input.sourceRef, input.observation, input.contentHash ?? null, input.observedAt ?? null, collectedAt, input.sensitivity);
|
|
108
|
+
});
|
|
109
|
+
const { db } = requireXopcDatabase();
|
|
110
|
+
return evidenceFromRow(db.prepare("SELECT * FROM work_understanding_evidence WHERE evidence_id = ?").get(id));
|
|
111
|
+
}
|
|
112
|
+
function updateWorkUnderstandingEvidenceObservation(id, observation) {
|
|
113
|
+
runSqliteWriteTransaction((db) => {
|
|
114
|
+
db.prepare("UPDATE work_understanding_evidence SET observation = ? WHERE evidence_id = ?").run(observation.slice(0, 1e3), id);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function listWorkUnderstandingEvidence(investigationId) {
|
|
118
|
+
const { db } = requireXopcDatabase();
|
|
119
|
+
return db.prepare("SELECT * FROM work_understanding_evidence WHERE investigation_id = ? ORDER BY collected_at ASC").all(investigationId).map(evidenceFromRow);
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { appendWorkUnderstandingEvidence, createWorkUnderstandingInvestigation, getWorkUnderstandingInvestigation, getWorkUnderstandingInvestigationForRun, listWorkUnderstandingEvidence, resetWorkUnderstandingInvestigation, updateWorkUnderstandingEvidenceObservation, updateWorkUnderstandingInvestigation };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
import type { WorkContextDocument, WorkContextSnapshot, WorkUnderstandingEvidenceItem, WorkUnderstandingInvestigation, WorkUnderstandingInvestigationBudget } from './types.js';
|
|
3
|
+
export declare const DEFAULT_WORK_INVESTIGATION_BUDGET: WorkUnderstandingInvestigationBudget;
|
|
4
|
+
type InvestigationAction = {
|
|
5
|
+
tool: 'read_text_excerpt';
|
|
6
|
+
relativePath: string;
|
|
7
|
+
reason: string;
|
|
8
|
+
} | {
|
|
9
|
+
tool: 'search_authorized_text';
|
|
10
|
+
query: string;
|
|
11
|
+
reason: string;
|
|
12
|
+
} | {
|
|
13
|
+
tool: 'finish';
|
|
14
|
+
reason: string;
|
|
15
|
+
};
|
|
16
|
+
export interface InvestigationDecision {
|
|
17
|
+
hypotheses: string[];
|
|
18
|
+
questions: string[];
|
|
19
|
+
evidenceSummaries: Array<{
|
|
20
|
+
evidenceId: string;
|
|
21
|
+
observation: string;
|
|
22
|
+
}>;
|
|
23
|
+
action: InvestigationAction;
|
|
24
|
+
}
|
|
25
|
+
interface RuntimeEvidence {
|
|
26
|
+
record: WorkUnderstandingEvidenceItem;
|
|
27
|
+
content: string;
|
|
28
|
+
modifiedAt?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface WorkInvestigationResult {
|
|
31
|
+
investigation: WorkUnderstandingInvestigation;
|
|
32
|
+
evidence: WorkUnderstandingEvidenceItem[];
|
|
33
|
+
documents: WorkContextDocument[];
|
|
34
|
+
degraded: boolean;
|
|
35
|
+
}
|
|
36
|
+
declare function chooseAction(input: {
|
|
37
|
+
config: Config;
|
|
38
|
+
snapshot: WorkContextSnapshot;
|
|
39
|
+
runtimeEvidence: RuntimeEvidence[];
|
|
40
|
+
toolCallsRemaining: number;
|
|
41
|
+
contentCharsRemaining: number;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
}): Promise<InvestigationDecision | null>;
|
|
44
|
+
export declare function investigateWorkContext(input: {
|
|
45
|
+
config: Config;
|
|
46
|
+
snapshot: WorkContextSnapshot;
|
|
47
|
+
rootPath: string;
|
|
48
|
+
discoveryRunId: string;
|
|
49
|
+
projectId: string;
|
|
50
|
+
sourceGrantId?: string;
|
|
51
|
+
budget?: Partial<WorkUnderstandingInvestigationBudget>;
|
|
52
|
+
decisionProvider?: typeof chooseAction;
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
}): Promise<WorkInvestigationResult>;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
|
|
4
|
+
import { init_providers, resolveModel } from "../providers/index.js";
|
|
5
|
+
import { completeWithResolvedCredentials } from "../providers/model-call.js";
|
|
6
|
+
import { readWorkDiscoveryTextExcerpt, searchWorkDiscoveryText } from "./probe.js";
|
|
7
|
+
import { appendWorkUnderstandingEvidence, createWorkUnderstandingInvestigation, getWorkUnderstandingInvestigationForRun, resetWorkUnderstandingInvestigation, updateWorkUnderstandingEvidenceObservation, updateWorkUnderstandingInvestigation } from "./investigation-repository.js";
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
//#region src/work-discovery/investigator.ts
|
|
10
|
+
init_schema();
|
|
11
|
+
init_providers();
|
|
12
|
+
init_logger();
|
|
13
|
+
const log = createLogger("WorkInvestigator");
|
|
14
|
+
const DEFAULT_WORK_INVESTIGATION_BUDGET = {
|
|
15
|
+
maxToolCalls: 6,
|
|
16
|
+
maxContentChars: 6e4,
|
|
17
|
+
maxDurationMs: 25e3
|
|
18
|
+
};
|
|
19
|
+
function extractText(content) {
|
|
20
|
+
if (typeof content === "string") return content;
|
|
21
|
+
if (!Array.isArray(content)) return "";
|
|
22
|
+
return content.map((part) => {
|
|
23
|
+
if (!part || typeof part !== "object") return "";
|
|
24
|
+
const item = part;
|
|
25
|
+
return item.type === "text" && typeof item.text === "string" ? item.text : "";
|
|
26
|
+
}).join("");
|
|
27
|
+
}
|
|
28
|
+
function parseObject(raw) {
|
|
29
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(raw)?.[1];
|
|
30
|
+
const start = raw.indexOf("{");
|
|
31
|
+
const end = raw.lastIndexOf("}");
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(fenced ?? (start >= 0 && end > start ? raw.slice(start, end + 1) : raw));
|
|
34
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function stringList(value, max, maxChars) {
|
|
40
|
+
return Array.isArray(value) ? value.flatMap((item) => typeof item === "string" && item.trim() ? [item.trim().slice(0, maxChars)] : []).slice(0, max) : [];
|
|
41
|
+
}
|
|
42
|
+
function decisionFromValue(value, allowedPaths) {
|
|
43
|
+
if (!value || typeof value !== "object") return null;
|
|
44
|
+
const item = value;
|
|
45
|
+
const rawAction = item.action;
|
|
46
|
+
if (!rawAction || typeof rawAction !== "object") return null;
|
|
47
|
+
const actionValue = rawAction;
|
|
48
|
+
const reason = typeof actionValue.reason === "string" ? actionValue.reason.trim().slice(0, 300) : "";
|
|
49
|
+
let action = null;
|
|
50
|
+
if (actionValue.tool === "finish") action = {
|
|
51
|
+
tool: "finish",
|
|
52
|
+
reason: reason || "Enough evidence was collected."
|
|
53
|
+
};
|
|
54
|
+
else if (actionValue.tool === "read_text_excerpt") {
|
|
55
|
+
const relativePath = typeof actionValue.relativePath === "string" ? actionValue.relativePath.trim() : "";
|
|
56
|
+
if (allowedPaths.has(relativePath)) action = {
|
|
57
|
+
tool: "read_text_excerpt",
|
|
58
|
+
relativePath,
|
|
59
|
+
reason
|
|
60
|
+
};
|
|
61
|
+
} else if (actionValue.tool === "search_authorized_text") {
|
|
62
|
+
const query = typeof actionValue.query === "string" ? actionValue.query.trim().slice(0, 120) : "";
|
|
63
|
+
if (query.length >= 2) action = {
|
|
64
|
+
tool: "search_authorized_text",
|
|
65
|
+
query,
|
|
66
|
+
reason
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!action) return null;
|
|
70
|
+
const evidenceSummaries = Array.isArray(item.evidenceSummaries) ? item.evidenceSummaries.flatMap((raw) => {
|
|
71
|
+
if (!raw || typeof raw !== "object") return [];
|
|
72
|
+
const summary = raw;
|
|
73
|
+
return typeof summary.evidenceId === "string" && typeof summary.observation === "string" ? [{
|
|
74
|
+
evidenceId: summary.evidenceId,
|
|
75
|
+
observation: summary.observation.trim().slice(0, 1e3)
|
|
76
|
+
}] : [];
|
|
77
|
+
}).slice(0, 20) : [];
|
|
78
|
+
return {
|
|
79
|
+
hypotheses: stringList(item.hypotheses, 6, 400),
|
|
80
|
+
questions: stringList(item.questions, 6, 400),
|
|
81
|
+
evidenceSummaries,
|
|
82
|
+
action
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function metadataForModel(snapshot) {
|
|
86
|
+
return {
|
|
87
|
+
root: snapshot.root,
|
|
88
|
+
structure: {
|
|
89
|
+
sampledPaths: snapshot.structure.sampledPaths.slice(0, 200),
|
|
90
|
+
omittedPathCount: snapshot.structure.omittedPathCount
|
|
91
|
+
},
|
|
92
|
+
git: snapshot.git,
|
|
93
|
+
candidateDocuments: snapshot.documents.slice(0, 30).map((document) => ({
|
|
94
|
+
relativePath: document.relativePath,
|
|
95
|
+
modifiedAt: document.modifiedAt,
|
|
96
|
+
selectionReason: document.selectionReason,
|
|
97
|
+
truncated: document.truncated
|
|
98
|
+
}))
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async function chooseAction(input) {
|
|
102
|
+
const modelRef = getAgentDefaultModelRef(input.config);
|
|
103
|
+
if (!modelRef) throw new Error("No default model configured");
|
|
104
|
+
const evidence = input.runtimeEvidence.slice(-16).map((item) => ({
|
|
105
|
+
evidenceId: item.record.id,
|
|
106
|
+
sourceType: item.record.sourceType,
|
|
107
|
+
sourceRef: item.record.sourceRef,
|
|
108
|
+
content: item.content.slice(0, 8e3)
|
|
109
|
+
}));
|
|
110
|
+
const prompt = [
|
|
111
|
+
"You are a bounded, read-only work investigation agent.",
|
|
112
|
+
"Your goal is to determine what the user is currently focused on and what work is being continuously advanced.",
|
|
113
|
+
"Form hypotheses, identify missing evidence, and choose exactly one next action.",
|
|
114
|
+
"Available actions are read_text_excerpt(relativePath), search_authorized_text(query), or finish.",
|
|
115
|
+
"Only choose relativePath values present in sampledPaths. Do not request secrets, credentials, personal traits, or unrelated private information.",
|
|
116
|
+
"Prefer evidence that distinguishes a current multi-day work thread from a one-off recent edit.",
|
|
117
|
+
"Use search only for a concise work topic visible in existing metadata or evidence.",
|
|
118
|
+
"Choose finish when evidence is sufficient or the remaining budget cannot materially improve the conclusion.",
|
|
119
|
+
"Return one JSON object with hypotheses, questions, evidenceSummaries, and action.",
|
|
120
|
+
"evidenceSummaries may paraphrase prior evidence by evidenceId; do not quote private content verbatim.",
|
|
121
|
+
`Remaining budget: ${input.toolCallsRemaining} tool calls, ${input.contentCharsRemaining} content characters.`,
|
|
122
|
+
JSON.stringify({
|
|
123
|
+
metadata: metadataForModel(input.snapshot),
|
|
124
|
+
evidence
|
|
125
|
+
})
|
|
126
|
+
].join("\n");
|
|
127
|
+
return decisionFromValue(parseObject(extractText((await completeWithResolvedCredentials(resolveModel(modelRef), { messages: [{
|
|
128
|
+
role: "user",
|
|
129
|
+
content: prompt,
|
|
130
|
+
timestamp: Date.now()
|
|
131
|
+
}] }, {
|
|
132
|
+
maxTokens: 1200,
|
|
133
|
+
temperature: .1,
|
|
134
|
+
signal: input.signal
|
|
135
|
+
})).content)), new Set(input.snapshot.structure.sampledPaths));
|
|
136
|
+
}
|
|
137
|
+
function contentHash(content) {
|
|
138
|
+
return createHash("sha256").update(content).digest("hex");
|
|
139
|
+
}
|
|
140
|
+
async function investigateWorkContext(input) {
|
|
141
|
+
const budget = {
|
|
142
|
+
maxToolCalls: Math.max(1, Math.min(12, input.budget?.maxToolCalls ?? DEFAULT_WORK_INVESTIGATION_BUDGET.maxToolCalls)),
|
|
143
|
+
maxContentChars: Math.max(4e3, Math.min(12e4, input.budget?.maxContentChars ?? DEFAULT_WORK_INVESTIGATION_BUDGET.maxContentChars)),
|
|
144
|
+
maxDurationMs: Math.max(100, Math.min(6e4, input.budget?.maxDurationMs ?? DEFAULT_WORK_INVESTIGATION_BUDGET.maxDurationMs))
|
|
145
|
+
};
|
|
146
|
+
const existing = getWorkUnderstandingInvestigationForRun(input.discoveryRunId);
|
|
147
|
+
let investigation = existing ? resetWorkUnderstandingInvestigation(existing.id, budget) : createWorkUnderstandingInvestigation({
|
|
148
|
+
discoveryRunId: input.discoveryRunId,
|
|
149
|
+
budget
|
|
150
|
+
});
|
|
151
|
+
investigation = updateWorkUnderstandingInvestigation(investigation.id, {
|
|
152
|
+
status: "investigating",
|
|
153
|
+
plan: {
|
|
154
|
+
hypotheses: [],
|
|
155
|
+
questions: []
|
|
156
|
+
},
|
|
157
|
+
toolCallCount: 0,
|
|
158
|
+
contentCharsRead: 0,
|
|
159
|
+
errorMessage: void 0,
|
|
160
|
+
completedAt: void 0
|
|
161
|
+
});
|
|
162
|
+
const startedAt = Date.now();
|
|
163
|
+
const deadlineSignal = AbortSignal.timeout(budget.maxDurationMs);
|
|
164
|
+
const investigationSignal = input.signal ? AbortSignal.any([input.signal, deadlineSignal]) : deadlineSignal;
|
|
165
|
+
const runtimeEvidence = [];
|
|
166
|
+
const documents = /* @__PURE__ */ new Map();
|
|
167
|
+
let degraded = false;
|
|
168
|
+
if (input.snapshot.git) {
|
|
169
|
+
const content = JSON.stringify(input.snapshot.git);
|
|
170
|
+
const record = appendWorkUnderstandingEvidence({
|
|
171
|
+
investigationId: investigation.id,
|
|
172
|
+
...input.sourceGrantId ? { sourceGrantId: input.sourceGrantId } : {},
|
|
173
|
+
projectId: input.projectId,
|
|
174
|
+
sourceType: "git",
|
|
175
|
+
sourceRef: "git://recent-state",
|
|
176
|
+
observation: `Collected recent Git state with ${input.snapshot.git.changedPaths.length} changed paths.`,
|
|
177
|
+
contentHash: contentHash(content),
|
|
178
|
+
collectedAt: Date.now(),
|
|
179
|
+
sensitivity: "normal"
|
|
180
|
+
});
|
|
181
|
+
runtimeEvidence.push({
|
|
182
|
+
record,
|
|
183
|
+
content
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
while (investigation.toolCallCount < budget.maxToolCalls && investigation.contentCharsRead < budget.maxContentChars && Date.now() - startedAt < budget.maxDurationMs) {
|
|
188
|
+
if (input.signal?.aborted) throw new DOMException("Work investigation canceled", "AbortError");
|
|
189
|
+
let decision = null;
|
|
190
|
+
try {
|
|
191
|
+
decision = await (input.decisionProvider ?? chooseAction)({
|
|
192
|
+
config: input.config,
|
|
193
|
+
snapshot: input.snapshot,
|
|
194
|
+
runtimeEvidence,
|
|
195
|
+
toolCallsRemaining: budget.maxToolCalls - investigation.toolCallCount,
|
|
196
|
+
contentCharsRemaining: budget.maxContentChars - investigation.contentCharsRead,
|
|
197
|
+
signal: investigationSignal
|
|
198
|
+
});
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (input.signal?.aborted) throw error;
|
|
201
|
+
degraded = true;
|
|
202
|
+
log.debug({
|
|
203
|
+
err: error,
|
|
204
|
+
investigationId: investigation.id,
|
|
205
|
+
phase: "planning"
|
|
206
|
+
}, "Work investigation planning degraded");
|
|
207
|
+
}
|
|
208
|
+
if (!decision) break;
|
|
209
|
+
for (const summary of decision.evidenceSummaries) if (runtimeEvidence.some((item) => item.record.id === summary.evidenceId) && summary.observation) {
|
|
210
|
+
updateWorkUnderstandingEvidenceObservation(summary.evidenceId, summary.observation);
|
|
211
|
+
const runtime = runtimeEvidence.find((item) => item.record.id === summary.evidenceId);
|
|
212
|
+
if (runtime) runtime.record = {
|
|
213
|
+
...runtime.record,
|
|
214
|
+
observation: summary.observation
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
investigation = updateWorkUnderstandingInvestigation(investigation.id, { plan: {
|
|
218
|
+
hypotheses: decision.hypotheses,
|
|
219
|
+
questions: decision.questions
|
|
220
|
+
} });
|
|
221
|
+
if (decision.action.tool === "finish") break;
|
|
222
|
+
investigation = updateWorkUnderstandingInvestigation(investigation.id, { toolCallCount: investigation.toolCallCount + 1 });
|
|
223
|
+
const charsRemaining = budget.maxContentChars - investigation.contentCharsRead;
|
|
224
|
+
try {
|
|
225
|
+
if (decision.action.tool === "read_text_excerpt") {
|
|
226
|
+
const result = await readWorkDiscoveryTextExcerpt({
|
|
227
|
+
rootPath: input.rootPath,
|
|
228
|
+
relativePath: decision.action.relativePath,
|
|
229
|
+
maxChars: Math.min(12e3, charsRemaining),
|
|
230
|
+
signal: investigationSignal
|
|
231
|
+
});
|
|
232
|
+
if (result.excerpt) {
|
|
233
|
+
const record = appendWorkUnderstandingEvidence({
|
|
234
|
+
investigationId: investigation.id,
|
|
235
|
+
...input.sourceGrantId ? { sourceGrantId: input.sourceGrantId } : {},
|
|
236
|
+
projectId: input.projectId,
|
|
237
|
+
sourceType: "file",
|
|
238
|
+
sourceRef: result.relativePath,
|
|
239
|
+
observation: `Read a bounded excerpt from ${result.relativePath}.`,
|
|
240
|
+
contentHash: contentHash(result.excerpt),
|
|
241
|
+
observedAt: result.modifiedAt,
|
|
242
|
+
sensitivity: "normal"
|
|
243
|
+
});
|
|
244
|
+
runtimeEvidence.push({
|
|
245
|
+
record,
|
|
246
|
+
content: result.excerpt,
|
|
247
|
+
modifiedAt: result.modifiedAt
|
|
248
|
+
});
|
|
249
|
+
documents.set(result.relativePath, {
|
|
250
|
+
relativePath: result.relativePath,
|
|
251
|
+
modifiedAt: result.modifiedAt,
|
|
252
|
+
excerpt: result.excerpt,
|
|
253
|
+
truncated: result.truncated,
|
|
254
|
+
selectionReason: `agent_investigation: ${decision.action.reason}`.slice(0, 300)
|
|
255
|
+
});
|
|
256
|
+
investigation = updateWorkUnderstandingInvestigation(investigation.id, { contentCharsRead: investigation.contentCharsRead + result.excerpt.length });
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
const results = await searchWorkDiscoveryText({
|
|
260
|
+
rootPath: input.rootPath,
|
|
261
|
+
relativePaths: input.snapshot.structure.sampledPaths,
|
|
262
|
+
query: decision.action.query,
|
|
263
|
+
signal: investigationSignal
|
|
264
|
+
});
|
|
265
|
+
let charsRead = 0;
|
|
266
|
+
for (const result of results) {
|
|
267
|
+
const excerpt = result.excerpt.slice(0, Math.max(0, charsRemaining - charsRead));
|
|
268
|
+
if (!excerpt) break;
|
|
269
|
+
charsRead += excerpt.length;
|
|
270
|
+
const record = appendWorkUnderstandingEvidence({
|
|
271
|
+
investigationId: investigation.id,
|
|
272
|
+
...input.sourceGrantId ? { sourceGrantId: input.sourceGrantId } : {},
|
|
273
|
+
projectId: input.projectId,
|
|
274
|
+
sourceType: "file",
|
|
275
|
+
sourceRef: result.relativePath,
|
|
276
|
+
observation: `Found a bounded match for "${decision.action.query}" in ${result.relativePath}.`,
|
|
277
|
+
contentHash: contentHash(excerpt),
|
|
278
|
+
observedAt: result.modifiedAt,
|
|
279
|
+
sensitivity: "normal"
|
|
280
|
+
});
|
|
281
|
+
runtimeEvidence.push({
|
|
282
|
+
record,
|
|
283
|
+
content: excerpt,
|
|
284
|
+
modifiedAt: result.modifiedAt
|
|
285
|
+
});
|
|
286
|
+
documents.set(result.relativePath, {
|
|
287
|
+
relativePath: result.relativePath,
|
|
288
|
+
modifiedAt: result.modifiedAt,
|
|
289
|
+
excerpt,
|
|
290
|
+
truncated: true,
|
|
291
|
+
selectionReason: `agent_search: ${decision.action.reason}`.slice(0, 300)
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
investigation = updateWorkUnderstandingInvestigation(investigation.id, { contentCharsRead: investigation.contentCharsRead + charsRead });
|
|
295
|
+
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
if (input.signal?.aborted) throw error;
|
|
298
|
+
degraded = true;
|
|
299
|
+
log.debug({
|
|
300
|
+
err: error,
|
|
301
|
+
investigationId: investigation.id,
|
|
302
|
+
tool: decision.action.tool,
|
|
303
|
+
phase: "tool_execution"
|
|
304
|
+
}, "Work investigation tool call skipped");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (documents.size === 0) {
|
|
308
|
+
degraded = true;
|
|
309
|
+
for (const document of input.snapshot.documents.slice(0, 6)) {
|
|
310
|
+
if (investigation.contentCharsRead >= budget.maxContentChars) break;
|
|
311
|
+
const excerpt = document.excerpt.slice(0, budget.maxContentChars - investigation.contentCharsRead);
|
|
312
|
+
if (!excerpt) continue;
|
|
313
|
+
const record = appendWorkUnderstandingEvidence({
|
|
314
|
+
investigationId: investigation.id,
|
|
315
|
+
...input.sourceGrantId ? { sourceGrantId: input.sourceGrantId } : {},
|
|
316
|
+
projectId: input.projectId,
|
|
317
|
+
sourceType: "file",
|
|
318
|
+
sourceRef: document.relativePath,
|
|
319
|
+
observation: `Used the bounded discovery excerpt from ${document.relativePath} as fallback evidence.`,
|
|
320
|
+
contentHash: contentHash(excerpt),
|
|
321
|
+
observedAt: document.modifiedAt,
|
|
322
|
+
sensitivity: "normal"
|
|
323
|
+
});
|
|
324
|
+
runtimeEvidence.push({
|
|
325
|
+
record,
|
|
326
|
+
content: excerpt,
|
|
327
|
+
modifiedAt: document.modifiedAt
|
|
328
|
+
});
|
|
329
|
+
documents.set(document.relativePath, {
|
|
330
|
+
...document,
|
|
331
|
+
excerpt,
|
|
332
|
+
selectionReason: "investigation_fallback"
|
|
333
|
+
});
|
|
334
|
+
investigation = updateWorkUnderstandingInvestigation(investigation.id, { contentCharsRead: investigation.contentCharsRead + excerpt.length });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
investigation = updateWorkUnderstandingInvestigation(investigation.id, {
|
|
338
|
+
status: "completed",
|
|
339
|
+
completedAt: Date.now()
|
|
340
|
+
});
|
|
341
|
+
return {
|
|
342
|
+
investigation,
|
|
343
|
+
evidence: runtimeEvidence.map((item) => item.record),
|
|
344
|
+
documents: [...documents.values()],
|
|
345
|
+
degraded
|
|
346
|
+
};
|
|
347
|
+
} catch (error) {
|
|
348
|
+
const canceled = input.signal?.aborted || error instanceof DOMException && error.name === "AbortError";
|
|
349
|
+
updateWorkUnderstandingInvestigation(investigation.id, {
|
|
350
|
+
status: canceled ? "canceled" : "failed",
|
|
351
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
352
|
+
completedAt: Date.now()
|
|
353
|
+
});
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
//#endregion
|
|
358
|
+
export { DEFAULT_WORK_INVESTIGATION_BUDGET, investigateWorkContext };
|
|
@@ -10,9 +10,31 @@ export declare function previewWorkDiscoveryRoot(rootPath: string): Promise<{
|
|
|
10
10
|
fingerprint: {
|
|
11
11
|
changedFileCount: number;
|
|
12
12
|
recentAreas: string[];
|
|
13
|
+
contentSignature: string;
|
|
13
14
|
generatedAt: number;
|
|
14
15
|
branch?: string;
|
|
15
16
|
};
|
|
16
17
|
}>;
|
|
17
18
|
export declare function probeWorkDiscoveryRoot(rootPath: string, signal?: AbortSignal): Promise<WorkContextSnapshot>;
|
|
19
|
+
export declare function readWorkDiscoveryTextExcerpt(input: {
|
|
20
|
+
rootPath: string;
|
|
21
|
+
relativePath: string;
|
|
22
|
+
maxChars?: number;
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
relativePath: string;
|
|
26
|
+
excerpt: string;
|
|
27
|
+
modifiedAt: number;
|
|
28
|
+
truncated: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function searchWorkDiscoveryText(input: {
|
|
31
|
+
rootPath: string;
|
|
32
|
+
relativePaths: string[];
|
|
33
|
+
query: string;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}): Promise<Array<{
|
|
36
|
+
relativePath: string;
|
|
37
|
+
excerpt: string;
|
|
38
|
+
modifiedAt: number;
|
|
39
|
+
}>>;
|
|
18
40
|
export declare function summarizeWorkContextSnapshot(snapshot: WorkContextSnapshot): WorkContextSnapshotSummary;
|