@xopcai/xopc 0.0.195 → 0.0.197
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/{agent-avatar-dicebear-DkYgzssq.js → agent-avatar-dicebear-C5st7lt5.js} +1 -1
- package/dist/gateway/static/root/assets/agents-Baxfj44y.js +68 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DVXLietl.js → app-management-settings-panel-S8LhoD6G.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-D7oohrYf.js → appearance-settings-D8Cd5vDP.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-0uCxKyE5.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-CpBzHKzI.js → archive-plugin-qL07mwnY.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DMWXe12h.js → attachment-load-CqSobpdi.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-XyDat125.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BM0MgsHB.js → binary-plugins-DBRPyLYE.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C2MT7mG3.js → block-editor-6wG1LU7t.js} +47 -47
- package/dist/gateway/static/root/assets/browser-settings-page-CrYNMR4w.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-V01qhcZc.js → browser-workflow-inputs-Abil4puY.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DPmSKVWx.js → browser-workflows-page-BEu3E0et.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CvMcDhGf.js +7 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CHJDY-Ih.js +3 -0
- package/dist/gateway/static/root/assets/channels-settings-Ds9BJbcY.js +1 -0
- package/dist/gateway/static/root/assets/connectors-api-CgWjgPSI.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-NUs-Zf7F.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-5SqAw4UD.js → cron-expression-ZdDBAoqA.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-eiaYMDYI.js → dependency-picker-BGeB1jpn.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-BtfzkmnU.js → desktop-pet-CsLR4pWB.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-Dn3hnBOU.js → desktop-pet-settings-CCjT1bdo.js} +1 -1
- package/dist/gateway/static/root/assets/directory-picker-path-field-C-Te1QN3.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-EWu0uOpw.js → extension-debug-page-CD73euAM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-2qZ7ngqL.js → extension-page-DAKjpNwd.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-4MOAwYPT.js → extension-settings-page-BLSNdlgd.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-aqPj1HAI.js → gateway-config-api-CQrf0k3D.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BbQBgKWH.js → gateway-settings-CvgH8IJI.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-DXtG-Sy0.js → heartbeat-settings-SPpnqbjl.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-BFoD6047.js +3 -0
- package/dist/gateway/static/root/assets/index-84ys9u-K.js +152 -0
- package/dist/gateway/static/root/assets/index-D-srnucP.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-WKmsr5WD.js → keyboard-shortcuts-settings-HMhxgOuD.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-D5uL2_Fd.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-3-aNfJwB.js → local-apps-page-DIWkFa3g.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page--6v8qq6y.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-D8vbsfLm.js → management-settings-DtEuS-kR.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-DRFl6Vfw.js → markdown-split-DvVBewS4.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-C5J46ROp.js → media-plugins-YVj7NVzD.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-Z0lEBC-X.js → notes-page-BDzuL2I9.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-IdjuNXvH.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-Dyj6Snbu.js → page-tabs-7bSEWfSX.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-CPDM4F7n.js → preview-open-alternatives-tgLbHgcV.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-8RFhWmcU.js → product-open-page-Bwx_CQht.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DnJXSuM4.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-DckZKlBI.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CfbUHBUH.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BBgWkYk0.js → runtime-tools-settings-panel-Fe05Nus6.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-BJqF0l7i.js → schema-form-CFfyC4CB.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BCfCh4My.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-Cbi4FvzO.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CYL5uBzc.js → settings-form-section-gEnEYT_3.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BabbixC0.js → settings-loading-skeleton-BRE_-7Da.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-B7OH9I8A.js → settings-page-C1zxCpqB.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-D9X3eVDo.js → settings-page-layout-CRpXF_05.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-BHdz-BO7.js → setup-status-panel-BcHdpmFf.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CMuJZ5Qq.js → share-preview-page-DU8L68A5.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-kjTqH9yY.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-QAGpwzIM.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-C9U1pIT-.js → skills-page-lE1-YRdK.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-C3iaLgk9.js → skills-page.utils-CYwFWTso.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-CAN01aY0.js → system-settings-panel-CVDsiPKn.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-DsM13-cy.js +1 -0
- package/dist/gateway/static/root/assets/{typed-models-lib-C9FMLeH2.js → typed-models-lib-DelyYgoc.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-AAZNoD6t.js → use-autosave-C50Mq5yQ.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-D-VEOt2A.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-yLXEYgwV.js → voice-api-key-field-DYfgTe3Y.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-tbkbg-8l.js → work-discovery-overlay-DPbujsp3.js} +1 -1
- package/dist/gateway/static/root/assets/work-discovery-page-D77opady.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BJHOxj4Z.js → workflow-run-setup-panel-DqIb1oBB.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-B9-PLmlX.js +5 -0
- package/dist/gateway/static/root/index.html +2 -2
- package/dist/package.js +1 -1
- package/dist/src/agent/embedded/execution-context.d.ts +2 -0
- package/dist/src/agent/embedded/execution-context.js +11 -0
- package/dist/src/agent/embedded/index.d.ts +3 -1
- package/dist/src/agent/embedded/index.js +5 -3
- package/dist/src/agent/embedded/run-turn.js +15 -9
- package/dist/src/agent/embedded/session-runner.d.ts +6 -11
- package/dist/src/agent/embedded/session-runner.js +25 -36
- package/dist/src/agent/embedded/transcript-runtime.d.ts +35 -0
- package/dist/src/agent/embedded/transcript-runtime.js +66 -0
- package/dist/src/agent/embedded/types.d.ts +3 -1
- package/dist/src/agent/service.d.ts +15 -0
- package/dist/src/agent/service.js +30 -0
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +1 -1
- package/dist/src/gateway/hono/routes/home.js +2 -2
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/projects.js +12 -1
- package/dist/src/gateway/hono/routes/side-chats.d.ts +3 -0
- package/dist/src/gateway/hono/routes/side-chats.js +173 -0
- package/dist/src/gateway/hono/routes/understanding-sources.js +5 -1
- package/dist/src/gateway/service/agent-runner.d.ts +4 -0
- package/dist/src/gateway/service/agent-runner.js +15 -1
- package/dist/src/gateway/service/run-gateway-agent.js +1 -1
- package/dist/src/gateway/service.d.ts +4 -0
- package/dist/src/gateway/service.js +33 -7
- package/dist/src/gateway/side-chat/context-snapshot.d.ts +11 -0
- package/dist/src/gateway/side-chat/context-snapshot.js +108 -0
- package/dist/src/gateway/side-chat/index.d.ts +5 -0
- package/dist/src/gateway/side-chat/index.js +4 -0
- package/dist/src/gateway/side-chat/manager.d.ts +45 -0
- package/dist/src/gateway/side-chat/manager.js +198 -0
- package/dist/src/gateway/side-chat/run-service.d.ts +22 -0
- package/dist/src/gateway/side-chat/run-service.js +110 -0
- package/dist/src/gateway/side-chat/types.d.ts +61 -0
- package/dist/src/gateway/side-chat/types.js +1 -0
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/routing/session-key-utils.d.ts +0 -1
- package/dist/src/routing/session-key-utils.js +1 -6
- package/dist/src/routing/session-key.js +2 -2
- package/dist/src/tasks/home-query-service.d.ts +24 -0
- package/dist/src/tasks/home-query-service.js +284 -5
- package/dist/src/tasks/index.js +3 -3
- package/dist/src/tasks/project-operating-view-service.d.ts +2 -1
- package/dist/src/tasks/project-operating-view-service.js +27 -4
- package/dist/src/user-context/sources/activity-clustering.js +1 -1
- package/dist/src/user-context/sources/index.js +2 -2
- package/dist/src/user-context/sources/repository.d.ts +1 -0
- package/dist/src/user-context/sources/repository.js +4 -1
- package/dist/src/work-discovery/analyzer.js +8 -8
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agents-COX-ZLtY.js +0 -68
- package/dist/gateway/static/root/assets/apps-page-S52mdBX_.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-DGGJQO9B.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-C_tkW-L_.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CPu6MIHF.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-ttuWLoiJ.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-DrWWVQjj.js +0 -1
- package/dist/gateway/static/root/assets/connectors-api-CG0UqhPN.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CyfIrY2l.js +0 -2
- package/dist/gateway/static/root/assets/directory-picker-path-field-Wa5zFvbb.js +0 -1
- package/dist/gateway/static/root/assets/home-page-k21J7B1q.js +0 -3
- package/dist/gateway/static/root/assets/index-DtEVsSU1.css +0 -1
- package/dist/gateway/static/root/assets/index-peR_-O6U.js +0 -150
- package/dist/gateway/static/root/assets/local-app-workbench-page-r8wlEj3A.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-OU3uRCoz.js +0 -2
- package/dist/gateway/static/root/assets/notes-workbench-B74ylIVP.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-3ugVthse.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-VVAyOeRA.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-C6XqOPzA.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BMj-t4hX.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-B7WvJXGJ.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-B0F1jbhj.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-Dnpq03tO.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-Bs5oS-wN.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-CRY8IE-7.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-Dtqgvs_0.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BBjCNaXn.js +0 -5
|
@@ -2,7 +2,6 @@ import { createLogger } from "../../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { guardSessionManager } from "./session-tool-result-guard.js";
|
|
4
4
|
import { transformUserMessageForPersistence } from "../inbound/attachment-pipeline.js";
|
|
5
|
-
import { openSqliteHydratingSessionManager } from "./sqlite-hydrating-session-manager.js";
|
|
6
5
|
import { createEmbeddedModelRuntime, resolveEmbeddedProviderApiKeySync } from "./model-runtime.js";
|
|
7
6
|
import { wrapStreamFnForXopcExtensions } from "./xopc-stream-bridge.js";
|
|
8
7
|
import { xopcToolsToDefinitions } from "./xopc-tools-bridge.js";
|
|
@@ -46,9 +45,7 @@ function createEmbeddedSettingsManager(cwd) {
|
|
|
46
45
|
return sm;
|
|
47
46
|
}
|
|
48
47
|
/**
|
|
49
|
-
* Owns the per-
|
|
50
|
-
* injectable owner; {@link defaultEmbeddedSessionRunnerPool} keeps the historic
|
|
51
|
-
* module-level free functions working until every caller is migrated to DI.
|
|
48
|
+
* Owns the per-runtime pool of pi `AgentSession` runners.
|
|
52
49
|
*/
|
|
53
50
|
var EmbeddedSessionRunnerPool = class {
|
|
54
51
|
pool = /* @__PURE__ */ new Map();
|
|
@@ -80,13 +77,13 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
80
77
|
evictions: 0
|
|
81
78
|
};
|
|
82
79
|
}
|
|
83
|
-
evict(
|
|
84
|
-
const entry = this.pool.get(
|
|
80
|
+
evict(runtimeId, reason = "explicit") {
|
|
81
|
+
const entry = this.pool.get(runtimeId);
|
|
85
82
|
if (!entry) return;
|
|
86
|
-
this.disposePooledRunner(
|
|
83
|
+
this.disposePooledRunner(runtimeId, entry, reason);
|
|
87
84
|
}
|
|
88
85
|
evictAll(reason = "dispose_all") {
|
|
89
|
-
for (const
|
|
86
|
+
for (const runtimeId of [...this.pool.keys()]) this.evict(runtimeId, reason);
|
|
90
87
|
}
|
|
91
88
|
async acquire(params) {
|
|
92
89
|
this.stats.acquires += 1;
|
|
@@ -100,7 +97,7 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
100
97
|
credentialRevision: providerCredentialRevision(params.model.provider)
|
|
101
98
|
});
|
|
102
99
|
const reuseEnabled = this.isEnabledFn();
|
|
103
|
-
const existing = this.pool.get(params.
|
|
100
|
+
const existing = this.pool.get(params.runtimeId);
|
|
104
101
|
let entry;
|
|
105
102
|
let reused = false;
|
|
106
103
|
if (reuseEnabled && existing && existing.fingerprint === fingerprint) {
|
|
@@ -111,13 +108,13 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
111
108
|
this.stats.reuses += 1;
|
|
112
109
|
applySystemPromptOverrideToSession(entry.session, params.systemPrompt);
|
|
113
110
|
entry.session.agent.streamFunction = entry.baseStreamFn;
|
|
114
|
-
log.debug({
|
|
111
|
+
log.debug({ runtimeId: params.runtimeId }, "Reusing pooled embedded session runner");
|
|
115
112
|
} else {
|
|
116
|
-
if (existing) this.disposePooledRunner(params.
|
|
113
|
+
if (existing) this.disposePooledRunner(params.runtimeId, existing, "fingerprint_mismatch");
|
|
117
114
|
entry = await this.createPooledRunner(params);
|
|
118
|
-
this.pool.set(params.
|
|
115
|
+
this.pool.set(params.runtimeId, entry);
|
|
119
116
|
this.stats.creates += 1;
|
|
120
|
-
log.debug({
|
|
117
|
+
log.debug({ runtimeId: params.runtimeId }, "Created embedded session runner");
|
|
121
118
|
}
|
|
122
119
|
return {
|
|
123
120
|
session: entry.session,
|
|
@@ -125,11 +122,11 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
125
122
|
reused,
|
|
126
123
|
release: () => {
|
|
127
124
|
if (!this.isEnabledFn()) {
|
|
128
|
-
this.disposePooledRunner(params.
|
|
125
|
+
this.disposePooledRunner(params.runtimeId, entry, "runner_disabled");
|
|
129
126
|
return;
|
|
130
127
|
}
|
|
131
128
|
entry.lastUsedAt = Date.now();
|
|
132
|
-
this.scheduleIdleEviction(params.
|
|
129
|
+
this.scheduleIdleEviction(params.runtimeId, entry);
|
|
133
130
|
}
|
|
134
131
|
};
|
|
135
132
|
}
|
|
@@ -139,37 +136,33 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
139
136
|
entry.idleTimer = null;
|
|
140
137
|
}
|
|
141
138
|
}
|
|
142
|
-
scheduleIdleEviction(
|
|
139
|
+
scheduleIdleEviction(runtimeId, entry) {
|
|
143
140
|
this.clearIdleTimer(entry);
|
|
144
141
|
const ttlMs = this.getIdleTtlMsFn();
|
|
145
142
|
entry.idleTimer = setTimeout(() => {
|
|
146
|
-
if (this.pool.get(
|
|
143
|
+
if (this.pool.get(runtimeId) === entry) this.disposePooledRunner(runtimeId, entry, "idle_ttl");
|
|
147
144
|
}, ttlMs);
|
|
148
145
|
entry.idleTimer.unref?.();
|
|
149
146
|
}
|
|
150
|
-
disposePooledRunner(
|
|
147
|
+
disposePooledRunner(runtimeId, entry, reason) {
|
|
151
148
|
this.clearIdleTimer(entry);
|
|
152
|
-
this.pool.delete(
|
|
149
|
+
this.pool.delete(runtimeId);
|
|
153
150
|
this.stats.evictions += 1;
|
|
154
151
|
try {
|
|
155
152
|
entry.piSm.flushPendingToolResults?.();
|
|
156
153
|
} catch {}
|
|
157
154
|
log.debug({
|
|
158
|
-
|
|
155
|
+
runtimeId,
|
|
159
156
|
reason
|
|
160
157
|
}, "Embedded session runner evicted");
|
|
161
158
|
}
|
|
162
159
|
async createPooledRunner(params) {
|
|
163
|
-
const {
|
|
160
|
+
const { runtimeId, sessionId, workspaceDir, model, thinkingLevel, tools, systemPrompt } = params;
|
|
164
161
|
const settingsManager = createEmbeddedSettingsManager(workspaceDir);
|
|
165
|
-
const piSm = guardSessionManager(
|
|
166
|
-
sessionKey,
|
|
167
|
-
sessionId,
|
|
168
|
-
cwd: workspaceDir
|
|
169
|
-
}), {
|
|
170
|
-
sessionKey,
|
|
162
|
+
const piSm = guardSessionManager(params.transcriptRuntime.openSessionManager(workspaceDir), {
|
|
163
|
+
sessionKey: params.transcriptRuntime.persistent ? runtimeId : void 0,
|
|
171
164
|
contextWindowTokens: model.contextWindow ?? 128e3,
|
|
172
|
-
transformMessageForPersistence: (message) => transformUserMessageForPersistence(
|
|
165
|
+
transformMessageForPersistence: params.transcriptRuntime.persistent ? (message) => transformUserMessageForPersistence(runtimeId, message) : void 0
|
|
173
166
|
});
|
|
174
167
|
const toolDefs = xopcToolsToDefinitions(tools);
|
|
175
168
|
const toolNames = tools.map((t) => t.name);
|
|
@@ -197,7 +190,7 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
197
190
|
const baseStreamFn = wrapStreamFnForXopcExtensions(session.agent.streamFunction);
|
|
198
191
|
session.agent.streamFunction = baseStreamFn;
|
|
199
192
|
return {
|
|
200
|
-
|
|
193
|
+
runtimeId,
|
|
201
194
|
fingerprint: buildEmbeddedRunnerFingerprint({
|
|
202
195
|
sessionId,
|
|
203
196
|
workspaceDir,
|
|
@@ -223,8 +216,8 @@ function getEmbeddedSessionRunnerStats() {
|
|
|
223
216
|
function resetEmbeddedSessionRunnerForTest() {
|
|
224
217
|
defaultEmbeddedSessionRunnerPool.resetForTest();
|
|
225
218
|
}
|
|
226
|
-
function evictEmbeddedSessionRunner(
|
|
227
|
-
defaultEmbeddedSessionRunnerPool.evict(
|
|
219
|
+
function evictEmbeddedSessionRunner(runtimeId, reason = "explicit") {
|
|
220
|
+
defaultEmbeddedSessionRunnerPool.evict(runtimeId, reason);
|
|
228
221
|
}
|
|
229
222
|
function evictAllEmbeddedSessionRunners(reason = "dispose_all") {
|
|
230
223
|
defaultEmbeddedSessionRunnerPool.evictAll(reason);
|
|
@@ -232,9 +225,5 @@ function evictAllEmbeddedSessionRunners(reason = "dispose_all") {
|
|
|
232
225
|
function acquireEmbeddedSessionRunner(params) {
|
|
233
226
|
return defaultEmbeddedSessionRunnerPool.acquire(params);
|
|
234
227
|
}
|
|
235
|
-
/** Resolve session identity used by embedded runner acquire and turn execution. */
|
|
236
|
-
async function resolveEmbeddedTranscriptInputs(sessionStore, sessionKey) {
|
|
237
|
-
return sessionStore.resolveTranscriptPath(sessionKey);
|
|
238
|
-
}
|
|
239
228
|
//#endregion
|
|
240
|
-
export { EmbeddedSessionRunnerPool, acquireEmbeddedSessionRunner, buildEmbeddedRunnerFingerprint, defaultEmbeddedSessionRunnerPool, evictAllEmbeddedSessionRunners, evictEmbeddedSessionRunner, getEmbeddedSessionRunnerIdleTtlMs, getEmbeddedSessionRunnerStats, isEmbeddedSessionRunnerEnabled, resetEmbeddedSessionRunnerForTest
|
|
229
|
+
export { EmbeddedSessionRunnerPool, acquireEmbeddedSessionRunner, buildEmbeddedRunnerFingerprint, defaultEmbeddedSessionRunnerPool, evictAllEmbeddedSessionRunners, evictEmbeddedSessionRunner, getEmbeddedSessionRunnerIdleTtlMs, getEmbeddedSessionRunnerStats, isEmbeddedSessionRunnerEnabled, resetEmbeddedSessionRunnerForTest };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AgentMessage } from '@earendil-works/pi-agent-core';
|
|
2
|
+
import { SessionManager } from '@earendil-works/pi-coding-agent';
|
|
3
|
+
import type { Api, Model } from '@earendil-works/pi-ai';
|
|
4
|
+
import { type CompactionExecutionOptions, type CompactionResult } from '../memory/compaction.js';
|
|
5
|
+
import type { SessionStore } from '../../session/store.js';
|
|
6
|
+
export interface EmbeddedTranscriptRuntime {
|
|
7
|
+
readonly runtimeId: string;
|
|
8
|
+
readonly sessionId: string;
|
|
9
|
+
readonly persistent: boolean;
|
|
10
|
+
openSessionManager(cwd: string): SessionManager;
|
|
11
|
+
loadMessages(): Promise<AgentMessage[]>;
|
|
12
|
+
compact(messages: AgentMessage[], model: Model<Api>, instructions?: string, force?: boolean, options?: CompactionExecutionOptions): Promise<CompactionResult>;
|
|
13
|
+
}
|
|
14
|
+
export declare function createSqliteTranscriptRuntime(params: {
|
|
15
|
+
sessionKey: string;
|
|
16
|
+
sessionStore: SessionStore;
|
|
17
|
+
}): Promise<EmbeddedTranscriptRuntime>;
|
|
18
|
+
export declare class InMemoryTranscriptRuntime implements EmbeddedTranscriptRuntime {
|
|
19
|
+
readonly persistent = false;
|
|
20
|
+
readonly runtimeId: string;
|
|
21
|
+
readonly sessionId: string;
|
|
22
|
+
private readonly sessionManager;
|
|
23
|
+
private readonly compactor;
|
|
24
|
+
private baselineEntryCount;
|
|
25
|
+
constructor(params: {
|
|
26
|
+
runtimeId: string;
|
|
27
|
+
cwd: string;
|
|
28
|
+
initialMessages?: readonly AgentMessage[];
|
|
29
|
+
});
|
|
30
|
+
openSessionManager(_cwd: string): SessionManager;
|
|
31
|
+
loadMessages(): Promise<AgentMessage[]>;
|
|
32
|
+
captureBaseline(): void;
|
|
33
|
+
loadConversationMessages(): AgentMessage[];
|
|
34
|
+
compact(messages: AgentMessage[], model: Model<Api>, instructions?: string, force?: boolean, options?: CompactionExecutionOptions): Promise<CompactionResult>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { SessionCompactor } from "../memory/compaction.js";
|
|
2
|
+
import { openSqliteHydratingSessionManager } from "./sqlite-hydrating-session-manager.js";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { SessionManager } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
//#region src/agent/embedded/transcript-runtime.ts
|
|
6
|
+
async function createSqliteTranscriptRuntime(params) {
|
|
7
|
+
const identity = await params.sessionStore.resolveTranscriptPath(params.sessionKey);
|
|
8
|
+
return {
|
|
9
|
+
runtimeId: params.sessionKey,
|
|
10
|
+
sessionId: identity.sessionId,
|
|
11
|
+
persistent: true,
|
|
12
|
+
openSessionManager: (cwd) => openSqliteHydratingSessionManager({
|
|
13
|
+
sessionKey: params.sessionKey,
|
|
14
|
+
sessionId: identity.sessionId,
|
|
15
|
+
cwd
|
|
16
|
+
}),
|
|
17
|
+
loadMessages: () => params.sessionStore.load(params.sessionKey),
|
|
18
|
+
compact: (messages, model, instructions, force, options) => params.sessionStore.compact(params.sessionKey, messages, model, instructions, force, options)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
var InMemoryTranscriptRuntime = class {
|
|
22
|
+
persistent = false;
|
|
23
|
+
runtimeId;
|
|
24
|
+
sessionId;
|
|
25
|
+
sessionManager;
|
|
26
|
+
compactor = new SessionCompactor();
|
|
27
|
+
baselineEntryCount = 0;
|
|
28
|
+
constructor(params) {
|
|
29
|
+
this.runtimeId = params.runtimeId;
|
|
30
|
+
this.sessionId = crypto.randomUUID();
|
|
31
|
+
this.sessionManager = SessionManager.inMemory(params.cwd, { id: this.sessionId });
|
|
32
|
+
for (const message of params.initialMessages ?? []) if (message.role === "compactionSummary") this.sessionManager.appendCustomMessageEntry("side-chat-parent-compaction", `The parent conversation was compacted into this summary:\n\n${message.summary}`, false);
|
|
33
|
+
else if (message.role === "branchSummary") this.sessionManager.appendCustomMessageEntry("side-chat-parent-branch", `The parent conversation includes this branch summary:\n\n${message.summary}`, false);
|
|
34
|
+
else this.sessionManager.appendMessage(message);
|
|
35
|
+
this.captureBaseline();
|
|
36
|
+
}
|
|
37
|
+
openSessionManager(_cwd) {
|
|
38
|
+
return this.sessionManager;
|
|
39
|
+
}
|
|
40
|
+
async loadMessages() {
|
|
41
|
+
return [...this.sessionManager.buildSessionContext().messages];
|
|
42
|
+
}
|
|
43
|
+
captureBaseline() {
|
|
44
|
+
this.baselineEntryCount = this.sessionManager.getBranch().length;
|
|
45
|
+
}
|
|
46
|
+
loadConversationMessages() {
|
|
47
|
+
return this.sessionManager.getBranch().slice(this.baselineEntryCount).flatMap((entry) => entry.type === "message" ? [entry.message] : []);
|
|
48
|
+
}
|
|
49
|
+
async compact(messages, model, instructions, force, options) {
|
|
50
|
+
const result = await this.compactor.compact(messages, model, instructions, force, options);
|
|
51
|
+
if (!result.compacted) return result;
|
|
52
|
+
const firstKept = this.sessionManager.getBranch().filter((entry) => entry.type === "message")[result.firstKeptIndex];
|
|
53
|
+
if (!firstKept) return {
|
|
54
|
+
...result,
|
|
55
|
+
compacted: false
|
|
56
|
+
};
|
|
57
|
+
this.sessionManager.appendCompaction(result.summary, firstKept.id, result.tokensBefore, {
|
|
58
|
+
plannerVersion: result.plannerVersion,
|
|
59
|
+
summaryModelRef: result.summaryModelRef,
|
|
60
|
+
qualityAudit: result.qualityAudit
|
|
61
|
+
});
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
export { InMemoryTranscriptRuntime, createSqliteTranscriptRuntime };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentMessage, AgentToolResult, ThinkingLevel } from '@earendil-works/pi-agent-core';
|
|
2
2
|
import type { AssistantMessageEvent, Model, Api, CacheRetention, ImageContent } from '@earendil-works/pi-ai';
|
|
3
3
|
import type { SessionStore } from '../../session/store.js';
|
|
4
|
+
import type { EmbeddedTranscriptRuntime } from './transcript-runtime.js';
|
|
4
5
|
export type EmbeddedStreamEvent = {
|
|
5
6
|
type: 'agent_start';
|
|
6
7
|
runId?: string;
|
|
@@ -93,7 +94,8 @@ export type RunXopcEmbeddedTurnParams = {
|
|
|
93
94
|
thinkingLevel?: ThinkingLevel;
|
|
94
95
|
cacheRetention?: CacheRetention;
|
|
95
96
|
workspaceDir: string;
|
|
96
|
-
sessionStore
|
|
97
|
+
sessionStore?: SessionStore;
|
|
98
|
+
transcriptRuntime?: EmbeddedTranscriptRuntime;
|
|
97
99
|
timeoutMs: number;
|
|
98
100
|
abortSignal?: AbortSignal;
|
|
99
101
|
onEvent?: (event: EmbeddedStreamEvent) => void;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import type { ThinkingLevel } from '@earendil-works/pi-agent-core';
|
|
1
2
|
import type { MessageBus } from '../infra/bus/index.js';
|
|
2
3
|
import { type Config } from '../config/schema.js';
|
|
3
4
|
import type { ChannelManager } from '../channels/manager.js';
|
|
4
5
|
import { SessionStore } from '../session/index.js';
|
|
6
|
+
import type { EmbeddedStreamEvent, RunXopcEmbeddedTurnResult } from './embedded/types.js';
|
|
7
|
+
import type { EmbeddedTranscriptRuntime } from './embedded/transcript-runtime.js';
|
|
5
8
|
import { OutboundCoordinator } from './messaging/index.js';
|
|
6
9
|
import { TurnDispatcher } from './inbound/turn-dispatcher.js';
|
|
7
10
|
import { SessionConfigService, SessionHydrator, SessionInspector } from './session/index.js';
|
|
@@ -114,6 +117,18 @@ export declare class AgentService {
|
|
|
114
117
|
refreshUserProfileContext(): void;
|
|
115
118
|
getMemoryManager(): import("./memory/manager.js").MemoryManager;
|
|
116
119
|
getModelForSession(sessionKey: string): string;
|
|
120
|
+
/** Run a full tool-capable turn against a caller-owned, non-persistent transcript. */
|
|
121
|
+
runEphemeralTurn(params: {
|
|
122
|
+
executionSessionKey: string;
|
|
123
|
+
parentSessionKey: string;
|
|
124
|
+
runId: string;
|
|
125
|
+
content: string;
|
|
126
|
+
modelRef: string;
|
|
127
|
+
thinkingLevel?: ThinkingLevel;
|
|
128
|
+
transcriptRuntime: EmbeddedTranscriptRuntime;
|
|
129
|
+
abortSignal?: AbortSignal;
|
|
130
|
+
onEvent?: (event: EmbeddedStreamEvent) => void;
|
|
131
|
+
}): Promise<RunXopcEmbeddedTurnResult>;
|
|
117
132
|
switchModelForSession(sessionKey: string, modelId: string): Promise<boolean>;
|
|
118
133
|
/**
|
|
119
134
|
* Clears per-session model override so the next turn uses the configured agent default
|
|
@@ -6,9 +6,11 @@ import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
|
|
|
6
6
|
import { applyConfigOverrides } from "../config/runtime-overrides.js";
|
|
7
7
|
import { init_agent_scope, resolveAgentHomeDir, resolveDefaultAgentId } from "./agent-scope.js";
|
|
8
8
|
import { extractProfileAgentId } from "../config/agent-profile.js";
|
|
9
|
+
import { init_providers, resolveModel } from "../providers/index.js";
|
|
9
10
|
import { extractTextContent } from "./context/workspace.js";
|
|
10
11
|
import { effectiveWorkspacePathForSession } from "../session/session-workspace.js";
|
|
11
12
|
import { getProjectForSession } from "../projects/workspace.js";
|
|
13
|
+
import { resolveAgentTurnTimeoutMs } from "./orchestration/run-agent-turn-with-timeout.js";
|
|
12
14
|
import { resolveResponseLanguageForSession } from "./prompt/response-language.js";
|
|
13
15
|
import { resolveWorkspaceSkillsDir, resolveWorkspaceSkillsLockPath } from "./skills/workspace-skills-dir.js";
|
|
14
16
|
import { removeSkillsLockEntry } from "./skills/hub-lock.js";
|
|
@@ -42,6 +44,8 @@ import "./middleware/index.js";
|
|
|
42
44
|
import { TurnDiffTracker } from "./coding/turn-diff-tracker.js";
|
|
43
45
|
import { LifecycleManager } from "./lifecycle/manager.js";
|
|
44
46
|
import "./lifecycle/index.js";
|
|
47
|
+
import { runXopcEmbeddedTurn } from "./embedded/run-turn.js";
|
|
48
|
+
import { runWithEmbeddedExecutionSession } from "./embedded/execution-context.js";
|
|
45
49
|
import { MessageRouter } from "./messaging/message-router.js";
|
|
46
50
|
import { CommandHandler } from "./messaging/command-handler.js";
|
|
47
51
|
import { StreamManager } from "./messaging/stream-manager.js";
|
|
@@ -68,6 +72,7 @@ import { readFile } from "node:fs/promises";
|
|
|
68
72
|
init_schema();
|
|
69
73
|
init_logger();
|
|
70
74
|
init_agent_scope();
|
|
75
|
+
init_providers();
|
|
71
76
|
const log = createLogger("AgentService");
|
|
72
77
|
function assistantMessageText(message) {
|
|
73
78
|
const content = message.content;
|
|
@@ -563,6 +568,31 @@ var AgentService = class {
|
|
|
563
568
|
getModelForSession(sessionKey) {
|
|
564
569
|
return this.modelManager.getModelForSession(sessionKey);
|
|
565
570
|
}
|
|
571
|
+
/** Run a full tool-capable turn against a caller-owned, non-persistent transcript. */
|
|
572
|
+
async runEphemeralTurn(params) {
|
|
573
|
+
const agent = this.agentManager.getOrCreateAgent(params.parentSessionKey);
|
|
574
|
+
const workspaceDir = this.agentManager.getResolvedWorkspaceForSession(params.parentSessionKey);
|
|
575
|
+
const model = resolveModel(params.modelRef);
|
|
576
|
+
return runWithEmbeddedExecutionSession(params.executionSessionKey, () => runXopcEmbeddedTurn({
|
|
577
|
+
sessionKey: params.executionSessionKey,
|
|
578
|
+
runId: params.runId,
|
|
579
|
+
userMessage: {
|
|
580
|
+
role: "user",
|
|
581
|
+
content: params.content,
|
|
582
|
+
timestamp: Date.now()
|
|
583
|
+
},
|
|
584
|
+
model,
|
|
585
|
+
modelRef: params.modelRef,
|
|
586
|
+
tools: agent.state.tools,
|
|
587
|
+
systemPrompt: agent.state.systemPrompt ?? "",
|
|
588
|
+
thinkingLevel: params.thinkingLevel ?? agent.state.thinkingLevel,
|
|
589
|
+
workspaceDir,
|
|
590
|
+
transcriptRuntime: params.transcriptRuntime,
|
|
591
|
+
timeoutMs: resolveAgentTurnTimeoutMs(this.effectiveAppConfig(), params.parentSessionKey),
|
|
592
|
+
abortSignal: params.abortSignal,
|
|
593
|
+
onEvent: params.onEvent
|
|
594
|
+
}));
|
|
595
|
+
}
|
|
566
596
|
async switchModelForSession(sessionKey, modelId) {
|
|
567
597
|
if (!await this.modelManager.switchModelForSession(sessionKey, modelId)) return false;
|
|
568
598
|
await this.sessionConfigStore.update(sessionKey, { modelOverride: modelId });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
|
|
2
1
|
import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
|
|
3
2
|
import "../agent-manifest/index.js";
|
|
3
|
+
import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
|
|
4
4
|
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
5
5
|
import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
6
6
|
//#region src/config/agent-profile.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
|
|
2
1
|
import { resolveCapabilityPresetLayer, resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
|
|
2
|
+
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
|
|
3
3
|
import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
|
|
4
4
|
import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
|
|
5
5
|
import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { shouldSilence, stripHeartbeatToken } from "../../heartbeat/tokens.js";
|
|
4
|
-
import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
|
|
5
4
|
import { isWithinActiveHours } from "../../heartbeat/active-hours.js";
|
|
6
5
|
import { isHeartbeatContentEmpty } from "../../heartbeat/content-check.js";
|
|
6
|
+
import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
|
|
7
7
|
import { createHeartbeatWake } from "../../heartbeat/wake.js";
|
|
8
8
|
import { resolveHeartbeatMdPath } from "../workspace-heartbeat-path.js";
|
|
9
9
|
import { readFile } from "fs/promises";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import type { AuthenticatedRouteDeps } from './deps.js';
|
|
3
|
-
export { buildHomeBriefing } from '../../../tasks/home-query-service.js';
|
|
3
|
+
export { buildHomeBriefing, buildHomeFocusItems } from '../../../tasks/home-query-service.js';
|
|
4
4
|
/** Register the unified work-home read model and its decision actions. */
|
|
5
5
|
export declare function registerHomeRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void;
|
|
@@ -2,7 +2,7 @@ import { acknowledgeHomeAttention } from "../../../storage/sqlite/home-attention
|
|
|
2
2
|
import { decideConnectorApproval } from "../../../storage/sqlite/connector-repository.js";
|
|
3
3
|
import "../../../storage/sqlite/index.js";
|
|
4
4
|
import { listGatewayAgents } from "../../agents-admin.js";
|
|
5
|
-
import { HomeQueryService, buildHomeBriefing } from "../../../tasks/home-query-service.js";
|
|
5
|
+
import { HomeQueryService, buildHomeBriefing, buildHomeFocusItems } from "../../../tasks/home-query-service.js";
|
|
6
6
|
//#region src/gateway/hono/routes/home.ts
|
|
7
7
|
/** Register the unified work-home read model and its decision actions. */
|
|
8
8
|
function registerHomeRoutes(authenticated, deps) {
|
|
@@ -90,4 +90,4 @@ function registerHomeRoutes(authenticated, deps) {
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
//#endregion
|
|
93
|
-
export { buildHomeBriefing, registerHomeRoutes };
|
|
93
|
+
export { buildHomeBriefing, buildHomeFocusItems, registerHomeRoutes };
|
|
@@ -2,6 +2,7 @@ import { registerActivityRoutes } from "./activity.js";
|
|
|
2
2
|
import { registerAgentStreamRoutes } from "./agent-stream.js";
|
|
3
3
|
import { registerDiscussionRoutes } from "./discussions.js";
|
|
4
4
|
import { registerSessionsRoutes } from "./sessions.js";
|
|
5
|
+
import { registerSideChatRoutes } from "./side-chats.js";
|
|
5
6
|
import { registerStatusRoutes } from "./status.js";
|
|
6
7
|
import { registerProjectsRoutes } from "./projects.js";
|
|
7
8
|
import { registerProjectSkillRoutes } from "./project-skills.js";
|
|
@@ -22,6 +23,7 @@ function registerCoreAuthenticatedRoutes(authenticated, deps) {
|
|
|
22
23
|
registerStatusRoutes(authenticated, deps);
|
|
23
24
|
registerAgentStreamRoutes(authenticated, deps);
|
|
24
25
|
registerSessionsRoutes(authenticated, deps);
|
|
26
|
+
registerSideChatRoutes(authenticated, deps);
|
|
25
27
|
registerActivityRoutes(authenticated, deps);
|
|
26
28
|
registerDiscussionRoutes(authenticated, deps);
|
|
27
29
|
registerProjectsRoutes(authenticated, deps);
|
|
@@ -16,6 +16,7 @@ import { buildProjectLoopOverview } from "../../../projects/project-loop.js";
|
|
|
16
16
|
import "../../../projects/index.js";
|
|
17
17
|
import { TaskApplicationService } from "../../../tasks/task-application-service.js";
|
|
18
18
|
import { defineTaskContract } from "../../../tasks/task-contract-definition.js";
|
|
19
|
+
import { ProjectOperatingViewService, summarizeProjectOperatingView } from "../../../tasks/project-operating-view-service.js";
|
|
19
20
|
import "../../../tasks/index.js";
|
|
20
21
|
import { classifyFileReferenceFsError } from "../../file-reference-errors.js";
|
|
21
22
|
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
@@ -313,6 +314,7 @@ function projectDigestMemoryRecordId(projectId) {
|
|
|
313
314
|
function registerProjectsRoutes(authenticated, deps) {
|
|
314
315
|
const { service } = deps;
|
|
315
316
|
const activity = new ActivityService();
|
|
317
|
+
const operatingViews = new ProjectOperatingViewService(service.projects);
|
|
316
318
|
authenticated.post("/api/projects", async (c) => {
|
|
317
319
|
const body = await c.req.json().catch(() => ({}));
|
|
318
320
|
const name = textField(body, "name")?.trim();
|
|
@@ -385,10 +387,19 @@ function registerProjectsRoutes(authenticated, deps) {
|
|
|
385
387
|
limit: parseLimit(c.req.query("limit")),
|
|
386
388
|
offset: c.req.query("offset") ? Math.max(0, Number.parseInt(c.req.query("offset"), 10) || 0) : void 0
|
|
387
389
|
});
|
|
390
|
+
const includeOperating = c.req.query("includeOperating") === "true";
|
|
388
391
|
return c.json({
|
|
389
392
|
ok: true,
|
|
390
393
|
...result,
|
|
391
|
-
items: result.items.map((project) =>
|
|
394
|
+
items: result.items.map((project) => {
|
|
395
|
+
const enriched = enrichProjectWorkspace(service, project);
|
|
396
|
+
if (!includeOperating) return enriched;
|
|
397
|
+
const view = operatingViews.get(project.id);
|
|
398
|
+
return {
|
|
399
|
+
...enriched,
|
|
400
|
+
operating: view ? summarizeProjectOperatingView(view) : void 0
|
|
401
|
+
};
|
|
402
|
+
})
|
|
392
403
|
});
|
|
393
404
|
});
|
|
394
405
|
authenticated.get("/api/projects/suggestions", async (c) => {
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { validateWebchatContent } from "../../chat-limits.js";
|
|
2
|
+
import { validateSideChatSelections } from "../../side-chat/context-snapshot.js";
|
|
3
|
+
import { SideChatError, parseThinkingLevel } from "../../side-chat/manager.js";
|
|
4
|
+
import "../../side-chat/index.js";
|
|
5
|
+
import { createGatewayRouteLogger, logRouteError } from "../lib/route-logger.js";
|
|
6
|
+
//#region src/gateway/hono/routes/side-chats.ts
|
|
7
|
+
const CLIENT_HEADER = "x-xopc-client-instance-id";
|
|
8
|
+
const log = createGatewayRouteLogger("SideChats");
|
|
9
|
+
function registerSideChatRoutes(authenticated, deps) {
|
|
10
|
+
const { service } = deps;
|
|
11
|
+
authenticated.post("/api/sessions/:parentSessionKey/side-chats", deps.chatRateLimitMiddleware, async (c) => {
|
|
12
|
+
try {
|
|
13
|
+
const body = await c.req.json().catch(() => ({}));
|
|
14
|
+
const clientInstanceId = readClientInstanceId(c, body.clientInstanceId);
|
|
15
|
+
if (body.modelRef !== void 0 && typeof body.modelRef !== "string") throw new SideChatError("modelRef must be a string", "INVALID_REQUEST");
|
|
16
|
+
const modelRef = typeof body.modelRef === "string" ? body.modelRef : void 0;
|
|
17
|
+
let selections;
|
|
18
|
+
try {
|
|
19
|
+
selections = validateSideChatSelections(body.selections);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
throw new SideChatError(error instanceof Error ? error.message : "Invalid selections", "INVALID_REQUEST");
|
|
22
|
+
}
|
|
23
|
+
const sideChat = await service.sideChats.create({
|
|
24
|
+
parentSessionKey: c.req.param("parentSessionKey"),
|
|
25
|
+
clientInstanceId,
|
|
26
|
+
selections,
|
|
27
|
+
config: {
|
|
28
|
+
modelRef,
|
|
29
|
+
thinkingLevel: parseThinkingLevel(body.thinkingLevel)
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return c.json({
|
|
33
|
+
ok: true,
|
|
34
|
+
sideChat
|
|
35
|
+
}, 201);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
return respondSideChatError(c, error);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
authenticated.get("/api/side-chats/:sideChatId", (c) => {
|
|
41
|
+
try {
|
|
42
|
+
const sideChat = service.sideChats.get(c.req.param("sideChatId"), readClientInstanceId(c));
|
|
43
|
+
return c.json({
|
|
44
|
+
ok: true,
|
|
45
|
+
sideChat
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return respondSideChatError(c, error);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
authenticated.get("/api/side-chats/:sideChatId/messages", (c) => {
|
|
52
|
+
try {
|
|
53
|
+
const messages = service.sideChats.getMessages(c.req.param("sideChatId"), readClientInstanceId(c));
|
|
54
|
+
return c.json({
|
|
55
|
+
ok: true,
|
|
56
|
+
messages
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
return respondSideChatError(c, error);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
authenticated.patch("/api/side-chats/:sideChatId/config", async (c) => {
|
|
63
|
+
try {
|
|
64
|
+
const body = await c.req.json().catch(() => ({}));
|
|
65
|
+
if (body.modelRef !== void 0 && typeof body.modelRef !== "string") throw new SideChatError("modelRef must be a string", "INVALID_REQUEST");
|
|
66
|
+
const modelRef = typeof body.modelRef === "string" ? body.modelRef : void 0;
|
|
67
|
+
const sideChat = service.sideChats.updateConfig(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), {
|
|
68
|
+
modelRef,
|
|
69
|
+
thinkingLevel: parseThinkingLevel(body.thinkingLevel)
|
|
70
|
+
});
|
|
71
|
+
return c.json({
|
|
72
|
+
ok: true,
|
|
73
|
+
sideChat
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return respondSideChatError(c, error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
authenticated.post("/api/side-chats/:sideChatId/heartbeat", (c) => {
|
|
80
|
+
try {
|
|
81
|
+
const sideChat = service.sideChats.heartbeat(c.req.param("sideChatId"), readClientInstanceId(c));
|
|
82
|
+
return c.json({
|
|
83
|
+
ok: true,
|
|
84
|
+
sideChat
|
|
85
|
+
});
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return respondSideChatError(c, error);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
authenticated.post("/api/side-chats/:sideChatId/inputs", deps.chatRateLimitMiddleware, async (c) => {
|
|
91
|
+
try {
|
|
92
|
+
const body = await c.req.json().catch(() => ({}));
|
|
93
|
+
const content = typeof body.content === "string" ? body.content : "";
|
|
94
|
+
const contentError = validateWebchatContent(content);
|
|
95
|
+
if (contentError) throw new SideChatError(contentError, "INVALID_REQUEST");
|
|
96
|
+
const result = service.sideChatRuns.submit(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), content);
|
|
97
|
+
return c.json({
|
|
98
|
+
ok: true,
|
|
99
|
+
payload: result
|
|
100
|
+
}, 202);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return respondSideChatError(c, error);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
authenticated.post("/api/side-chats/:sideChatId/abort", deps.chatRateLimitMiddleware, async (c) => {
|
|
106
|
+
try {
|
|
107
|
+
const body = await c.req.json().catch(() => ({}));
|
|
108
|
+
const aborted = await service.sideChatRuns.abort(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), typeof body.runId === "string" ? body.runId : void 0);
|
|
109
|
+
return c.json({
|
|
110
|
+
ok: true,
|
|
111
|
+
payload: { aborted }
|
|
112
|
+
});
|
|
113
|
+
} catch (error) {
|
|
114
|
+
return respondSideChatError(c, error);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
authenticated.post("/api/side-chats/:sideChatId/clarify/:requestId", deps.chatRateLimitMiddleware, async (c) => {
|
|
118
|
+
try {
|
|
119
|
+
const body = await c.req.json().catch(() => ({}));
|
|
120
|
+
const answer = body.skip === true ? "" : typeof body.answer === "string" ? body.answer.trim() : "";
|
|
121
|
+
if (body.skip !== true && !answer) throw new SideChatError("answer is required", "INVALID_REQUEST");
|
|
122
|
+
if (!service.sideChatRuns.submitClarification(c.req.param("sideChatId"), readClientInstanceId(c, body.clientInstanceId), c.req.param("requestId"), answer)) throw new SideChatError("Clarification request not found", "NOT_FOUND");
|
|
123
|
+
return c.json({ ok: true });
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return respondSideChatError(c, error);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
authenticated.delete("/api/side-chats/:sideChatId", async (c) => {
|
|
129
|
+
try {
|
|
130
|
+
return await service.sideChatRuns.dispose(c.req.param("sideChatId"), readClientInstanceId(c)) ? c.json({ ok: true }) : c.json({
|
|
131
|
+
ok: false,
|
|
132
|
+
error: "Side chat not found",
|
|
133
|
+
code: "NOT_FOUND"
|
|
134
|
+
}, 404);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return respondSideChatError(c, error);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
authenticated.delete("/api/side-chats", async (c) => {
|
|
140
|
+
try {
|
|
141
|
+
const removed = await service.sideChats.disposeClient(readClientInstanceId(c, c.req.query("clientInstanceId")));
|
|
142
|
+
return c.json({
|
|
143
|
+
ok: true,
|
|
144
|
+
removed
|
|
145
|
+
});
|
|
146
|
+
} catch (error) {
|
|
147
|
+
return respondSideChatError(c, error);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function readClientInstanceId(c, fallback) {
|
|
152
|
+
const value = c.req.header(CLIENT_HEADER) || (typeof fallback === "string" ? fallback : "");
|
|
153
|
+
if (!value.trim()) throw new SideChatError("clientInstanceId is required", "INVALID_REQUEST");
|
|
154
|
+
return value.trim();
|
|
155
|
+
}
|
|
156
|
+
function respondSideChatError(c, error) {
|
|
157
|
+
if (!(error instanceof SideChatError)) {
|
|
158
|
+
logRouteError(log, c, error, "Side chat request failed");
|
|
159
|
+
return c.json({
|
|
160
|
+
ok: false,
|
|
161
|
+
error: "Side chat request failed",
|
|
162
|
+
code: "INTERNAL_ERROR"
|
|
163
|
+
}, 500);
|
|
164
|
+
}
|
|
165
|
+
const status = error.code === "NOT_FOUND" ? 404 : error.code === "CONFLICT" ? 409 : error.code === "LIMIT_REACHED" ? 429 : 400;
|
|
166
|
+
return c.json({
|
|
167
|
+
ok: false,
|
|
168
|
+
error: error.message,
|
|
169
|
+
code: error.code
|
|
170
|
+
}, status);
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
export { registerSideChatRoutes };
|