fuli-context 0.7.6 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -13
- package/README.zh-CN.md +60 -14
- package/dist/web/assets/{AboutPage-sLV9WChi.js → AboutPage-BcZeFcHe.js} +1 -1
- package/dist/web/assets/{ConnectionsPage-BWn4ywGJ.js → ConnectionsPage-xAQYl1SQ.js} +1 -1
- package/dist/web/assets/EmployeeRecruitDialog-CbPAmhy7.js +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-CfFlyKSh.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-BQvTLoc8.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-DF3EL0Ui.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-UnnBDt0I.js +1 -0
- package/dist/web/assets/{KnowledgeEditDialog-DWUV_NPp.css → KnowledgeEditDialog-iv-dgUeD.css} +1 -1
- package/dist/web/assets/{KnowledgeInspector-CRQWOaos.js → KnowledgeInspector-BqPJH5Rr.js} +1 -1
- package/dist/web/assets/{KnowledgeOrganizerPage-Dfj3vIpU.js → KnowledgeOrganizerPage-CyvRflXM.js} +1 -1
- package/dist/web/assets/KnowledgePage-59eczTqe.js +1 -0
- package/dist/web/assets/{KnowledgeWorkspace-ChEB5Bwk.js → KnowledgeWorkspace-CfIjhOog.js} +1 -1
- package/dist/web/assets/{OverviewPage-Cd66M0RT.js → OverviewPage-Xyfm5xkZ.js} +1 -1
- package/dist/web/assets/{PersonalProfilePage-RCFHL0Wz.js → PersonalProfilePage-DB9mByB3.js} +1 -1
- package/dist/web/assets/PersonalProjectsPage-_-YXVi5O.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-C3vW6wmk.css +1 -0
- package/dist/web/assets/ProjectAgentsPage-DeeQByPX.js +11 -0
- package/dist/web/assets/{PublicProjectsPage-mstPEjHe.js → PublicProjectsPage-BEZ1YPs3.js} +1 -1
- package/dist/web/assets/{ReviewPage-6Y1SmfZy.js → ReviewPage-CQYGwFBH.js} +1 -1
- package/dist/web/assets/SearchableSelect-D27H0MoP.js +1 -0
- package/dist/web/assets/{SettingsPage--LdTMUm7.js → SettingsPage-BlEZ03Yi.js} +1 -1
- package/dist/web/assets/{WritingTastePage-CIpKswvs.js → WritingTastePage-DvRt_nmP.js} +1 -1
- package/dist/web/assets/catalog-DFvIaHVS.js +1 -0
- package/dist/web/assets/{console-BT1P2Db4.js → console-tOxOl8Vq.js} +1 -1
- package/dist/web/assets/conversation-launcher-settings-DuFSpPAo.js +1 -0
- package/dist/web/assets/{i18n-js6gfc7j.js → i18n-CgBHZthI.js} +3 -3
- package/dist/web/assets/{identity-CfDfanpa.js → identity-CFo_Uw1H.js} +1 -1
- package/dist/web/assets/index-CJc5ppXH.css +1 -0
- package/dist/web/assets/index-yCi3cz2l.js +2 -0
- package/dist/web/assets/{model-DJkLAJsg.js → model-BtnVr7fX.js} +1 -1
- package/dist/web/assets/{useApi-CROJJdhE-BdSti7Y2.js → useApi-CROJJdhE-B6MHm_Av.js} +1 -1
- package/dist/web/assets/{vue-router-Kk67EaCP.js → vue-router-CzHm-y-x.js} +1 -1
- package/dist/web/index.html +7 -6
- package/docs/employee-agents.md +99 -0
- package/docs/project-agent-memory.md +479 -0
- package/graph-provider/fuli_graph/knowledge_audit_models.py +171 -0
- package/graph-provider/fuli_graph/model_base.py +5 -0
- package/graph-provider/fuli_graph/model_validation.py +32 -0
- package/graph-provider/fuli_graph/models.py +26 -170
- package/graph-provider/fuli_graph/project_agent_context_models.py +29 -0
- package/graph-provider/fuli_graph/project_agent_executor_models.py +35 -7
- package/graph-provider/fuli_graph/project_agent_memory_models.py +79 -0
- package/graph-provider/fuli_graph/project_agent_memory_routes.py +46 -0
- package/graph-provider/fuli_graph/project_agent_models.py +9 -0
- package/graph-provider/fuli_graph/project_agent_recruitment_values.py +48 -0
- package/graph-provider/fuli_graph/project_agent_routes.py +21 -1
- package/graph-provider/fuli_graph/project_agent_task_models.py +217 -29
- package/graph-provider/fuli_graph/runtime.py +37 -1
- package/graph-provider/fuli_graph/store.py +6 -0
- package/graph-provider/fuli_graph/store_project_agent_context.py +65 -0
- package/graph-provider/fuli_graph/store_project_agent_executor_learning.py +175 -11
- package/graph-provider/fuli_graph/store_project_agent_executor_routing.py +33 -10
- package/graph-provider/fuli_graph/store_project_agent_executors.py +181 -14
- package/graph-provider/fuli_graph/store_project_agent_memory.py +174 -0
- package/graph-provider/fuli_graph/store_project_agent_task_activity.py +423 -0
- package/graph-provider/fuli_graph/store_project_agent_task_persistence.py +152 -0
- package/graph-provider/fuli_graph/store_project_agent_task_reads.py +187 -21
- package/graph-provider/fuli_graph/store_project_agent_task_recruitment.py +748 -162
- package/graph-provider/fuli_graph/store_project_agent_task_staffing.py +230 -18
- package/graph-provider/fuli_graph/store_project_agent_tasks.py +261 -468
- package/graph-provider/fuli_graph/store_project_agents.py +214 -46
- package/graph-provider/fuli_graph/store_task_contexts.py +217 -0
- package/graph-provider/fuli_graph/store_transactions.py +40 -0
- package/graph-provider/fuli_graph/task_context_models.py +50 -0
- package/graph-provider/fuli_graph/task_context_routes.py +31 -0
- package/graph-provider/fuli_graph/workflow_observation_models.py +1 -1
- package/graph-provider/pyproject.toml +1 -1
- package/npm-shrinkwrap.json +8 -8
- package/package.json +5 -2
- package/skills/capturing-session-knowledge/SKILL.md +18 -6
- package/src/adaptive-runtime/executor-pool.js +46 -5
- package/src/adaptive-runtime/graph-services.js +10 -3
- package/src/adaptive-runtime/lease-client.js +66 -14
- package/src/adaptive-runtime/runtime-broker.js +24 -9
- package/src/agent-tools/employee-definitions.js +43 -0
- package/src/agent-tools/graph-definitions.js +25 -6
- package/src/agent-tools/graph-handlers.js +11 -0
- package/src/agent-tools/project-agent-definitions.js +35 -4
- package/src/agent-tools/project-agent-memory-definitions.js +36 -0
- package/src/agent-tools.js +6 -2
- package/src/agents/codex/lifecycle-hook.js +107 -0
- package/src/agents/codex/lifecycle-hooks.js +231 -0
- package/src/agents/cursor/lifecycle-hook.js +133 -0
- package/src/agents/cursor/lifecycle-hooks.js +50 -0
- package/src/agents/lifecycle-message.js +19 -0
- package/src/app/agent-request-context.js +23 -0
- package/src/cli/command-registry.js +2 -0
- package/src/cli/employee-command.js +17 -0
- package/src/cli/remote-mcp-command.js +282 -0
- package/src/cli/setup-command.js +5 -0
- package/src/cli.js +10 -0
- package/src/employees/catalog/jefa.json +21 -0
- package/src/employees/install-package.js +77 -0
- package/src/employees/management-policy.js +88 -0
- package/src/employees/manifest.js +53 -0
- package/src/employees/package-registry.js +107 -0
- package/src/employees/project-selection.js +50 -0
- package/src/employees/recruitment.js +199 -0
- package/src/employees/service.js +83 -0
- package/src/employees/task-entry.js +39 -0
- package/src/graphiti/agent-knowledge-workflows.js +135 -25
- package/src/graphiti/federated-application.js +78 -35
- package/src/graphiti/project-agent-control-plane.js +20 -3
- package/src/graphiti/project-agent-mapping.js +155 -5
- package/src/graphiti/project-agent-memory.js +115 -0
- package/src/graphiti/project-agent-task-entry.js +126 -0
- package/src/graphiti/project-agent-workflows.js +30 -14
- package/src/graphiti/provider-client.js +66 -4
- package/src/http/api-router.js +25 -5
- package/src/http/employee-api-router.js +64 -0
- package/src/http/error-mapping.js +4 -0
- package/src/http/graph-api-router.js +2 -0
- package/src/http/request-policy.js +6 -3
- package/src/http/static-handler.js +4 -3
- package/src/mcp/create-mcp-server.js +98 -37
- package/src/mcp/direct-call.js +38 -0
- package/src/mcp/instructions.js +8 -7
- package/src/mcp/provider-task-context-registry.js +74 -0
- package/src/mcp/remote-http-server.js +761 -0
- package/src/mcp/session-id.js +29 -3
- package/src/mcp/task-context-registry.js +88 -29
- package/src/mcp/tool-annotations.js +10 -2
- package/src/mcp/tool-result.js +8 -3
- package/src/mcp-server.js +20 -8
- package/src/native-runtime/runtime.js +58 -8
- package/src/server.js +76 -28
- package/src/setup/agent-installation-status.js +38 -6
- package/src/setup/agents.js +20 -8
- package/src/setup/claude-code-config.js +55 -13
- package/src/setup/codex-bootstrap.js +11 -10
- package/src/setup/codex-config.js +74 -7
- package/src/setup/config-backup.js +18 -2
- package/src/setup/cursor-config.js +22 -5
- package/src/setup/setup.js +30 -22
- package/src/storage/json-file.js +11 -3
- package/dist/web/assets/KnowledgeEditDialog-CZ5ziPrD.js +0 -1
- package/dist/web/assets/KnowledgePage-BRYC9S5Y.js +0 -1
- package/dist/web/assets/PersonalProjectsPage-DEh8XWby.js +0 -1
- package/dist/web/assets/ProjectAgentsPage-Crh7PrXa.css +0 -1
- package/dist/web/assets/ProjectAgentsPage-DPnaH-TR.js +0 -11
- package/dist/web/assets/SearchableSelect-D3HM8YF8.js +0 -1
- package/dist/web/assets/conversation-launcher-settings-DrJEotdf.js +0 -1
- package/dist/web/assets/index-BnH5mcZx.css +0 -1
- package/dist/web/assets/index-GqJf1xqg.js +0 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { dirname } from 'node:path';
|
|
2
|
+
import { createEmployeeService } from '../employees/service.js';
|
|
2
3
|
|
|
3
4
|
import { GraphitiProviderClient } from './provider-client.js';
|
|
4
5
|
import {
|
|
@@ -30,7 +31,7 @@ import {
|
|
|
30
31
|
} from './source-marker.js';
|
|
31
32
|
import { resolvePersonalProjectPath } from './project-path-context.js';
|
|
32
33
|
import { mergeExternalKnowledgeProjection } from '../external-knowledge/graph-projection.js';
|
|
33
|
-
import {
|
|
34
|
+
import { ProviderTaskContextRegistry } from '../mcp/provider-task-context-registry.js';
|
|
34
35
|
import { attachExternalKnowledgeRuntime } from '../external-knowledge/runtime.js';
|
|
35
36
|
import { resolveSetupPaths } from '../setup/paths.js';
|
|
36
37
|
import {
|
|
@@ -79,6 +80,7 @@ import {
|
|
|
79
80
|
getCollaborationPreferences as getCollaborationPreferencesWorkflow
|
|
80
81
|
} from './collaboration-preference-workflow.js';
|
|
81
82
|
import { buildUserTasteSkill } from './user-taste-skill.js';
|
|
83
|
+
import { resolveTaskEntryAgent, loadProjectAgentContinuity } from './project-agent-task-entry.js';
|
|
82
84
|
import { getWritingTasteProfile as getWritingTasteProfileWorkflow } from './writing-taste-profile-workflow.js';
|
|
83
85
|
import {
|
|
84
86
|
groupSubscriptions,
|
|
@@ -114,6 +116,7 @@ export function openFederatedGraphApplication({
|
|
|
114
116
|
env,
|
|
115
117
|
fetchImpl
|
|
116
118
|
});
|
|
119
|
+
app.employees = createEmployeeService({ app, runtimeConfigPath });
|
|
117
120
|
}
|
|
118
121
|
return app;
|
|
119
122
|
}
|
|
@@ -137,7 +140,7 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
137
140
|
agentAccessPolicyStore = new AgentAccessPolicyStore(),
|
|
138
141
|
consoleUrl = sourceConsoleUrl(null),
|
|
139
142
|
projectPathResolver = resolvePersonalProjectPath,
|
|
140
|
-
taskContextRegistry =
|
|
143
|
+
taskContextRegistry = null,
|
|
141
144
|
providerRequestTimeoutMs = undefined
|
|
142
145
|
} = {}) {
|
|
143
146
|
super();
|
|
@@ -147,7 +150,6 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
147
150
|
this.agentAccessPolicyStore = agentAccessPolicyStore;
|
|
148
151
|
this.consoleUrl = consoleUrl;
|
|
149
152
|
this.projectPathResolver = projectPathResolver;
|
|
150
|
-
this.taskContextRegistry = taskContextRegistry;
|
|
151
153
|
this.personal = new GraphitiProviderClient({
|
|
152
154
|
baseUrl: config.personal.providerUrl,
|
|
153
155
|
accessToken: config.personal.accessToken,
|
|
@@ -155,6 +157,9 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
155
157
|
fetchImpl,
|
|
156
158
|
requestTimeoutMs: providerRequestTimeoutMs
|
|
157
159
|
});
|
|
160
|
+
this.taskContextRegistry = taskContextRegistry ?? new ProviderTaskContextRegistry(
|
|
161
|
+
this.personal, config.personal.spaceId
|
|
162
|
+
);
|
|
158
163
|
this.workspaces = new Map(config.workspaces.map((workspace) => {
|
|
159
164
|
const provider = createWorkspaceProvider(workspace, {
|
|
160
165
|
fetchImpl, requestTimeoutMs: providerRequestTimeoutMs
|
|
@@ -171,8 +176,8 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
171
176
|
return checkpointTaskKnowledgeWorkflow(this, input);
|
|
172
177
|
}
|
|
173
178
|
|
|
174
|
-
verifyTaskCheckpoint({ sessionId }) {
|
|
175
|
-
return this.taskContextRegistry.verify(sessionId);
|
|
179
|
+
verifyTaskCheckpoint({ sessionId, sourceApplication = 'other' }) {
|
|
180
|
+
return this.taskContextRegistry.verify(sessionId, sourceApplication);
|
|
176
181
|
}
|
|
177
182
|
|
|
178
183
|
async recordDecisionTrace(input) {
|
|
@@ -180,6 +185,10 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
180
185
|
return recordDecisionTraceWorkflow(this, input);
|
|
181
186
|
}
|
|
182
187
|
|
|
188
|
+
validateCaptureSessionKnowledge(input) {
|
|
189
|
+
if (this.getCapturePolicy().enabled) this.#prepareKnowledgeCapture(input);
|
|
190
|
+
}
|
|
191
|
+
|
|
183
192
|
async captureSessionKnowledge(input) {
|
|
184
193
|
const capturePolicy = this.getCapturePolicy();
|
|
185
194
|
if (!capturePolicy.enabled) {
|
|
@@ -189,15 +198,8 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
189
198
|
capturePolicy
|
|
190
199
|
};
|
|
191
200
|
}
|
|
192
|
-
|
|
193
|
-
const episode = providerEpisode(input);
|
|
201
|
+
const { episode, workspace } = this.#prepareKnowledgeCapture(input);
|
|
194
202
|
if (input.targetKind === 'personal') {
|
|
195
|
-
if (input.spaceId !== this.config.personal.spaceId) {
|
|
196
|
-
throw new ApplicationError(
|
|
197
|
-
ApplicationErrorCode.VALIDATION,
|
|
198
|
-
'Personal capture target must be the active personal space'
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
203
|
const result = await this.personal.commit({
|
|
202
204
|
space_id: input.spaceId,
|
|
203
205
|
personal_project_id: input.personalProjectId ?? null,
|
|
@@ -206,20 +208,6 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
206
208
|
});
|
|
207
209
|
return { route: 'personal', ...result };
|
|
208
210
|
}
|
|
209
|
-
if (input.projectAgentId) {
|
|
210
|
-
throw new ApplicationError(
|
|
211
|
-
ApplicationErrorCode.VALIDATION,
|
|
212
|
-
'Project Agent knowledge can only be captured in the personal graph'
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
if (episode.sensitivity !== 'normal') {
|
|
216
|
-
throw new ApplicationError(
|
|
217
|
-
ApplicationErrorCode.VALIDATION,
|
|
218
|
-
'Private or restricted knowledge cannot enter a team-shared project queue. Use targetKind "personal" with personalProjectId to keep it in the personal graph'
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
assertPublicKnowledgeEligible(episode);
|
|
222
|
-
const workspace = this.#workspace(input.providerUrl);
|
|
223
211
|
const draft = await this.personal.createPublicationDraft({
|
|
224
212
|
personal_space_id: this.config.personal.spaceId,
|
|
225
213
|
target_project_id: input.spaceId,
|
|
@@ -257,19 +245,33 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
257
245
|
projectAgentId = null,
|
|
258
246
|
projectPath = null,
|
|
259
247
|
taskPrompt = null,
|
|
248
|
+
sourceApplication = 'other',
|
|
249
|
+
sourceSessionId = null,
|
|
250
|
+
sessionId = null,
|
|
251
|
+
turnId = null,
|
|
252
|
+
workKind = null,
|
|
253
|
+
requiredCapabilities = [],
|
|
260
254
|
limit = 100,
|
|
261
255
|
agentInvocation = false,
|
|
262
256
|
agentToolName = 'get_collaboration_preferences'
|
|
263
257
|
} = {}) {
|
|
264
|
-
const projectResolution = await this.#resolvePreferenceProject({
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
258
|
+
const projectResolution = await this.#resolvePreferenceProject({ personalProjectId, projectPath });
|
|
259
|
+
const selection = projectPath === null && !personalProjectId && !projectAgentId
|
|
260
|
+
? null
|
|
261
|
+
: await resolveTaskEntryAgent(
|
|
262
|
+
this, projectResolution, { projectAgentId, taskPrompt, sourceApplication,
|
|
263
|
+
sessionId: agentToolName === 'get_collaboration_preferences'
|
|
264
|
+
? sessionId ?? sourceSessionId : turnId ? sessionId : null,
|
|
265
|
+
turnId: agentToolName === 'begin_task_context' ? turnId : null,
|
|
266
|
+
workKind, requiredCapabilities, agentInvocation, agentToolName }
|
|
267
|
+
);
|
|
268
|
+
// A rejected explicit role must not leak its private preferences via fallback.
|
|
269
|
+
const selectedAgentId = selection ? selection.agent?.agentId ?? null : projectAgentId;
|
|
270
|
+
const preferences = await getCollaborationPreferencesWorkflow(
|
|
269
271
|
this,
|
|
270
272
|
projectResolution,
|
|
271
273
|
{
|
|
272
|
-
projectAgentId,
|
|
274
|
+
projectAgentId: selectedAgentId,
|
|
273
275
|
taskPrompt,
|
|
274
276
|
limit,
|
|
275
277
|
agentInvocation,
|
|
@@ -277,6 +279,19 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
277
279
|
},
|
|
278
280
|
(items, toolName) => this.#recordAgentViews(items, toolName)
|
|
279
281
|
);
|
|
282
|
+
const management = this.employees && agentInvocation &&
|
|
283
|
+
['begin_task_context', 'get_collaboration_preferences'].includes(agentToolName)
|
|
284
|
+
? await this.employees.taskEntry({ personalProjectId: projectResolution.personalProjectId,
|
|
285
|
+
sourceApplication, sourceSessionId, sessionId })
|
|
286
|
+
: null;
|
|
287
|
+
const managedPreferences = management ? { ...preferences, project_management_context: management } : preferences;
|
|
288
|
+
if (!selection) return managedPreferences;
|
|
289
|
+
const context = selection.agent ? await loadProjectAgentContinuity(this, {
|
|
290
|
+
projectId: projectResolution.personalProjectId, agent: selection.agent,
|
|
291
|
+
sourceApplication, taskPrompt, selectionReason: selection.reason,
|
|
292
|
+
matchBasis: selection.match_basis
|
|
293
|
+
}) : selection;
|
|
294
|
+
return { ...managedPreferences, project_agent_context: context };
|
|
280
295
|
}
|
|
281
296
|
|
|
282
297
|
async getUserTasteSkill({
|
|
@@ -518,7 +533,7 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
518
533
|
|
|
519
534
|
async searchCurrentProjectKnowledge(input) {
|
|
520
535
|
const resolution = await this.#resolvePreferenceProject({
|
|
521
|
-
personalProjectId: null,
|
|
536
|
+
personalProjectId: input.personalProjectId ?? null,
|
|
522
537
|
projectPath: input.projectPath
|
|
523
538
|
});
|
|
524
539
|
return searchCurrentProjectKnowledgeWorkflow(this, resolution, input);
|
|
@@ -1164,7 +1179,7 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
1164
1179
|
};
|
|
1165
1180
|
}
|
|
1166
1181
|
|
|
1167
|
-
close() {}
|
|
1182
|
+
close() { return this.employees?.close(); }
|
|
1168
1183
|
|
|
1169
1184
|
async #recordAgentViews(items, toolName) {
|
|
1170
1185
|
const unique = new Map(items.map((item) => [
|
|
@@ -1195,6 +1210,34 @@ export class FederatedGraphApplication extends ProjectAgentControlPlaneApplicati
|
|
|
1195
1210
|
return this.#resolvePreferenceProject(input);
|
|
1196
1211
|
}
|
|
1197
1212
|
|
|
1213
|
+
#prepareKnowledgeCapture(input) {
|
|
1214
|
+
assertNoCredentials(input);
|
|
1215
|
+
const episode = providerEpisode(input);
|
|
1216
|
+
if (input.targetKind === 'personal') {
|
|
1217
|
+
if (input.spaceId !== this.config.personal.spaceId) {
|
|
1218
|
+
throw new ApplicationError(
|
|
1219
|
+
ApplicationErrorCode.VALIDATION,
|
|
1220
|
+
'Personal capture target must be the active personal space'
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
return { episode };
|
|
1224
|
+
}
|
|
1225
|
+
if (input.projectAgentId) {
|
|
1226
|
+
throw new ApplicationError(
|
|
1227
|
+
ApplicationErrorCode.VALIDATION,
|
|
1228
|
+
'Project Agent knowledge can only be captured in the personal graph'
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
if (episode.sensitivity !== 'normal') {
|
|
1232
|
+
throw new ApplicationError(
|
|
1233
|
+
ApplicationErrorCode.VALIDATION,
|
|
1234
|
+
'Private or restricted knowledge cannot enter a team-shared project queue. Use targetKind "personal" with personalProjectId to keep it in the personal graph'
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
assertPublicKnowledgeEligible(episode);
|
|
1238
|
+
return { episode, workspace: this.#workspace(input.providerUrl) };
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1198
1241
|
#workspace(providerUrl) {
|
|
1199
1242
|
const requested = providerUrl
|
|
1200
1243
|
? canonicalProviderUrl(providerUrl)
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { agentProjectResolution } from './agent-knowledge-workflows.js';
|
|
2
|
+
import {
|
|
3
|
+
getProjectAgentMemory,
|
|
4
|
+
checkpointProjectAgentMemory
|
|
5
|
+
} from './project-agent-memory.js';
|
|
2
6
|
import {
|
|
3
7
|
authorizeExecutor as authorizeExecutorWorkflow,
|
|
4
8
|
cleanupProjectAgentTestRoles as cleanupProjectAgentTestRolesWorkflow,
|
|
@@ -48,6 +52,16 @@ export const projectAgentControlPlaneHooks = Object.freeze({
|
|
|
48
52
|
});
|
|
49
53
|
|
|
50
54
|
export class ProjectAgentControlPlaneApplication {
|
|
55
|
+
async getProjectAgentMemory(input) {
|
|
56
|
+
this.#assertSpace(input.personalSpaceId);
|
|
57
|
+
return getProjectAgentMemory(this, input);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async checkpointProjectAgentMemory(input) {
|
|
61
|
+
this.#assertSpace(input.personalSpaceId);
|
|
62
|
+
return checkpointProjectAgentMemory(this, input);
|
|
63
|
+
}
|
|
64
|
+
|
|
51
65
|
async upsertProjectAgent(input) {
|
|
52
66
|
this.#assertSpace(input.personalSpaceId);
|
|
53
67
|
return upsertProjectAgentWorkflow(this, input);
|
|
@@ -252,7 +266,10 @@ export class ProjectAgentControlPlaneApplication {
|
|
|
252
266
|
}
|
|
253
267
|
|
|
254
268
|
async getProjectAgentContext(input) {
|
|
255
|
-
const resolution = await this.#resolveProject(
|
|
269
|
+
const resolution = await this.#resolveProject(
|
|
270
|
+
input.projectPath,
|
|
271
|
+
input.personalProjectId ?? null
|
|
272
|
+
);
|
|
256
273
|
return getProjectAgentContextWorkflow(
|
|
257
274
|
this,
|
|
258
275
|
agentProjectResolution(resolution),
|
|
@@ -266,9 +283,9 @@ export class ProjectAgentControlPlaneApplication {
|
|
|
266
283
|
);
|
|
267
284
|
}
|
|
268
285
|
|
|
269
|
-
#resolveProject(projectPath) {
|
|
286
|
+
#resolveProject(projectPath, personalProjectId = null) {
|
|
270
287
|
return this[projectAgentControlPlaneHooks.resolvePreferenceProject]({
|
|
271
|
-
personalProjectId
|
|
288
|
+
personalProjectId,
|
|
272
289
|
projectPath
|
|
273
290
|
});
|
|
274
291
|
}
|
|
@@ -246,6 +246,8 @@ export function providerProjectAgentTaskSubmit(input) {
|
|
|
246
246
|
objective: input.objective,
|
|
247
247
|
work_kind: input.workKind ?? input.work_kind,
|
|
248
248
|
required_capabilities: input.requiredCapabilities ?? input.required_capabilities ?? [],
|
|
249
|
+
executor_capability_hints:
|
|
250
|
+
input.executorCapabilityHints ?? input.executor_capability_hints ?? [],
|
|
249
251
|
duration: input.duration ?? 'ongoing',
|
|
250
252
|
staffing_intent: input.staffingIntent ?? input.staffing_intent ?? 'reuse_preferred',
|
|
251
253
|
lead_agent_id: input.leadAgentId ?? input.lead_agent_id ?? null,
|
|
@@ -293,6 +295,36 @@ export function projectAgentParallelPlan(value = {}) {
|
|
|
293
295
|
};
|
|
294
296
|
}
|
|
295
297
|
|
|
298
|
+
export function providerProjectAgentTokenUsage(value) {
|
|
299
|
+
if (value === undefined || value === null) return value ?? null;
|
|
300
|
+
return {
|
|
301
|
+
source: value.source,
|
|
302
|
+
total_tokens: value.totalTokens ?? value.total_tokens,
|
|
303
|
+
input_tokens: value.inputTokens ?? value.input_tokens ?? null,
|
|
304
|
+
output_tokens: value.outputTokens ?? value.output_tokens ?? null,
|
|
305
|
+
cached_input_tokens: value.cachedInputTokens ?? value.cached_input_tokens ?? null,
|
|
306
|
+
cache_write_input_tokens: value.cacheWriteInputTokens ??
|
|
307
|
+
value.cache_write_input_tokens ?? null,
|
|
308
|
+
reasoning_output_tokens: value.reasoningOutputTokens ??
|
|
309
|
+
value.reasoning_output_tokens ?? null
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function projectAgentTokenUsage(value) {
|
|
314
|
+
if (value === undefined || value === null) return value ?? null;
|
|
315
|
+
return {
|
|
316
|
+
source: value.source,
|
|
317
|
+
totalTokens: value.total_tokens ?? value.totalTokens,
|
|
318
|
+
inputTokens: value.input_tokens ?? value.inputTokens ?? null,
|
|
319
|
+
outputTokens: value.output_tokens ?? value.outputTokens ?? null,
|
|
320
|
+
cachedInputTokens: value.cached_input_tokens ?? value.cachedInputTokens ?? null,
|
|
321
|
+
cacheWriteInputTokens: value.cache_write_input_tokens ??
|
|
322
|
+
value.cacheWriteInputTokens ?? null,
|
|
323
|
+
reasoningOutputTokens: value.reasoning_output_tokens ??
|
|
324
|
+
value.reasoningOutputTokens ?? null
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
296
328
|
export function providerProjectAgentTaskActivity(input) {
|
|
297
329
|
const result = withoutUndefined({
|
|
298
330
|
personal_space_id: input.personalSpaceId ?? input.personal_space_id,
|
|
@@ -332,6 +364,31 @@ export function providerProjectAgentTaskActivity(input) {
|
|
|
332
364
|
worker_status: input.workerStatus ?? input.worker_status ?? null
|
|
333
365
|
});
|
|
334
366
|
}
|
|
367
|
+
if (hasAny(input, ['tokenUsage', 'token_usage'])) {
|
|
368
|
+
result.token_usage = providerProjectAgentTokenUsage(
|
|
369
|
+
input.tokenUsage ?? input.token_usage
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
if (hasAny(input, ['workerRuntime', 'worker_runtime'])) {
|
|
373
|
+
const runtime = input.workerRuntime ?? input.worker_runtime;
|
|
374
|
+
result.worker_runtime = runtime ? withoutUndefined({
|
|
375
|
+
application: runtime.application,
|
|
376
|
+
session_id: runtime.sessionId ?? runtime.session_id ?? null,
|
|
377
|
+
session_url: runtime.sessionUrl ?? runtime.session_url ?? null
|
|
378
|
+
}) : null;
|
|
379
|
+
}
|
|
380
|
+
copyOptional(
|
|
381
|
+
result,
|
|
382
|
+
'source_session_url',
|
|
383
|
+
input.sourceSessionUrl ?? input.source_session_url ?? null,
|
|
384
|
+
hasAny(input, ['sourceSessionUrl', 'source_session_url'])
|
|
385
|
+
);
|
|
386
|
+
copyOptional(
|
|
387
|
+
result,
|
|
388
|
+
'tools_used',
|
|
389
|
+
input.toolsUsed ?? input.tools_used ?? null,
|
|
390
|
+
hasAny(input, ['toolsUsed', 'tools_used'])
|
|
391
|
+
);
|
|
335
392
|
return result;
|
|
336
393
|
}
|
|
337
394
|
|
|
@@ -344,6 +401,7 @@ export function projectAgentTaskRecord(value = {}) {
|
|
|
344
401
|
objective: value.objective,
|
|
345
402
|
workKind: value.work_kind,
|
|
346
403
|
requiredCapabilities: value.required_capabilities ?? [],
|
|
404
|
+
executorCapabilityHints: value.executor_capability_hints ?? [],
|
|
347
405
|
duration: value.duration,
|
|
348
406
|
staffingIntent: value.staffing_intent,
|
|
349
407
|
status: value.status,
|
|
@@ -411,7 +469,7 @@ export function projectAgentTaskParticipantRecord(value = {}) {
|
|
|
411
469
|
}
|
|
412
470
|
|
|
413
471
|
export function projectAgentTaskEventRecord(value = {}) {
|
|
414
|
-
|
|
472
|
+
const result = {
|
|
415
473
|
eventId: value.event_id,
|
|
416
474
|
taskId: value.task_id,
|
|
417
475
|
agentId: value.agent_id ?? null,
|
|
@@ -439,6 +497,31 @@ export function projectAgentTaskEventRecord(value = {}) {
|
|
|
439
497
|
fallbackUsed: value.fallback_used ?? false,
|
|
440
498
|
createdAt: value.created_at
|
|
441
499
|
};
|
|
500
|
+
copyOptional(
|
|
501
|
+
result,
|
|
502
|
+
'workerRuntime',
|
|
503
|
+
projectAgentWorkerRuntime(value.worker_runtime ?? value.workerRuntime),
|
|
504
|
+
hasAny(value, ['worker_runtime', 'workerRuntime'])
|
|
505
|
+
);
|
|
506
|
+
copyOptional(
|
|
507
|
+
result,
|
|
508
|
+
'sourceSessionUrl',
|
|
509
|
+
value.source_session_url ?? value.sourceSessionUrl ?? null,
|
|
510
|
+
hasAny(value, ['source_session_url', 'sourceSessionUrl'])
|
|
511
|
+
);
|
|
512
|
+
copyOptional(
|
|
513
|
+
result,
|
|
514
|
+
'toolsUsed',
|
|
515
|
+
value.tools_used ?? value.toolsUsed ?? null,
|
|
516
|
+
hasAny(value, ['tools_used', 'toolsUsed'])
|
|
517
|
+
);
|
|
518
|
+
copyOptional(
|
|
519
|
+
result,
|
|
520
|
+
'tokenUsage',
|
|
521
|
+
projectAgentTokenUsage(value.token_usage ?? value.tokenUsage),
|
|
522
|
+
hasAny(value, ['token_usage', 'tokenUsage'])
|
|
523
|
+
);
|
|
524
|
+
return result;
|
|
442
525
|
}
|
|
443
526
|
|
|
444
527
|
export function projectAgentRoutingDecisionRecord(value = {}) {
|
|
@@ -483,6 +566,7 @@ export function projectAgentTaskRouteResult(value = {}) {
|
|
|
483
566
|
task: projectAgentTaskRecord(value.task ?? {}),
|
|
484
567
|
assignedAgent: value.assigned_agent ? projectAgentRecord(value.assigned_agent) : null,
|
|
485
568
|
recruitment: value.recruitment ? projectAgentRecruitmentRecord(value.recruitment) : null,
|
|
569
|
+
recruitments: (value.recruitments ?? []).map(projectAgentRecruitmentRecord),
|
|
486
570
|
decision: value.decision,
|
|
487
571
|
mustDiscloseRecruitment: value.must_disclose_recruitment ?? false,
|
|
488
572
|
clientNotice: value.client_notice ?? null
|
|
@@ -505,6 +589,8 @@ export function projectAgentRecruitmentRecord(value = {}) {
|
|
|
505
589
|
status: value.status,
|
|
506
590
|
confirmationMode: value.confirmation_mode,
|
|
507
591
|
proposedAgentId: value.proposed_agent_id,
|
|
592
|
+
participantRole: value.participant_role ?? 'lead',
|
|
593
|
+
recruitmentSlot: value.recruitment_slot ?? 'lead',
|
|
508
594
|
proposedProfile: value.proposed_profile
|
|
509
595
|
? projectAgentProfileRecord(value.proposed_profile) : null,
|
|
510
596
|
triggerSourceApplication: value.trigger_source_application ?? null,
|
|
@@ -542,10 +628,10 @@ export function projectAgentExecutionSummary(value) {
|
|
|
542
628
|
if (!Array.isArray(value)) return [];
|
|
543
629
|
return value.map((entry = {}) => {
|
|
544
630
|
const actualExecutor = entry.actual_executor_id ?? entry.actual_executor ??
|
|
545
|
-
entry.actualExecutor ??
|
|
631
|
+
entry.actualExecutor ?? null;
|
|
546
632
|
const workSummary = entry.work_summary ?? entry.workSummary ?? entry.summary ?? null;
|
|
547
633
|
const status = entry.status ?? entry.worker_status ?? entry.workerStatus ?? null;
|
|
548
|
-
|
|
634
|
+
const result = {
|
|
549
635
|
agentId: entry.agent_id ?? entry.agentId ?? null,
|
|
550
636
|
agentName: entry.agent_name ?? entry.agentName ?? null,
|
|
551
637
|
occupationEmoji: entry.occupation_emoji ?? entry.occupationEmoji ?? null,
|
|
@@ -563,8 +649,48 @@ export function projectAgentExecutionSummary(value) {
|
|
|
563
649
|
workSummary,
|
|
564
650
|
summary: workSummary,
|
|
565
651
|
status,
|
|
566
|
-
workerStatus: entry.worker_status ?? entry.workerStatus ??
|
|
652
|
+
workerStatus: entry.worker_status ?? entry.workerStatus ?? null
|
|
567
653
|
};
|
|
654
|
+
copyOptional(
|
|
655
|
+
result,
|
|
656
|
+
'workerRuntime',
|
|
657
|
+
projectAgentWorkerRuntime(entry.worker_runtime ?? entry.workerRuntime),
|
|
658
|
+
hasAny(entry, ['worker_runtime', 'workerRuntime'])
|
|
659
|
+
);
|
|
660
|
+
copyOptional(
|
|
661
|
+
result,
|
|
662
|
+
'sourceSessionId',
|
|
663
|
+
entry.source_session_id ?? entry.sourceSessionId ?? null,
|
|
664
|
+
hasAny(entry, ['source_session_id', 'sourceSessionId'])
|
|
665
|
+
);
|
|
666
|
+
copyOptional(
|
|
667
|
+
result,
|
|
668
|
+
'sourceSessionUrl',
|
|
669
|
+
entry.source_session_url ?? entry.sourceSessionUrl ?? null,
|
|
670
|
+
hasAny(entry, ['source_session_url', 'sourceSessionUrl'])
|
|
671
|
+
);
|
|
672
|
+
copyOptional(
|
|
673
|
+
result,
|
|
674
|
+
'toolsUsed',
|
|
675
|
+
entry.tools_used ?? entry.toolsUsed ?? null,
|
|
676
|
+
hasAny(entry, ['tools_used', 'toolsUsed'])
|
|
677
|
+
);
|
|
678
|
+
copyOptional(
|
|
679
|
+
result,
|
|
680
|
+
'tokenUsage',
|
|
681
|
+
projectAgentTokenUsage(entry.token_usage ?? entry.tokenUsage),
|
|
682
|
+
hasAny(entry, ['token_usage', 'tokenUsage'])
|
|
683
|
+
);
|
|
684
|
+
return result;
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
export function projectAgentWorkerRuntime(value) {
|
|
689
|
+
if (!value || typeof value !== 'object') return null;
|
|
690
|
+
return withoutUndefined({
|
|
691
|
+
application: value.application,
|
|
692
|
+
sessionId: value.session_id ?? value.sessionId ?? null,
|
|
693
|
+
sessionUrl: value.session_url ?? value.sessionUrl ?? null
|
|
568
694
|
});
|
|
569
695
|
}
|
|
570
696
|
|
|
@@ -587,12 +713,30 @@ export function projectAgentActivityRecord(value = {}) {
|
|
|
587
713
|
summary: task.summary,
|
|
588
714
|
occurredAt: task.occurred_at,
|
|
589
715
|
sourceApplication: task.source_application ?? null,
|
|
716
|
+
sourceSessionId: task.source_session_id ?? null,
|
|
717
|
+
sourceSessionUrl: task.source_session_url ?? task.sourceSessionUrl ?? null,
|
|
718
|
+
toolsUsed: task.tools_used ?? task.toolsUsed ?? null,
|
|
590
719
|
actualExecutor: task.actual_executor_id ?? task.actual_executor ?? null,
|
|
720
|
+
selectedExecutorId: task.selected_executor_id ?? null,
|
|
721
|
+
executorRuleId: task.executor_rule_id ?? task.rule_id ?? null,
|
|
591
722
|
matchedExecutorRuleId: task.matched_executor_rule_id ?? task.routing_rule_id ?? null,
|
|
592
723
|
executorSelectionReason: task.executor_selection_reason ?? null,
|
|
724
|
+
executorFallbackReason: task.executor_fallback_reason ?? null,
|
|
725
|
+
executorFallbackOutcome: task.executor_fallback_outcome ?? null,
|
|
726
|
+
executorBlockedReason: task.executor_blocked_reason ?? null,
|
|
727
|
+
executorDecision: task.executor_decision ?? null,
|
|
593
728
|
auditId: task.audit_id ?? null,
|
|
594
729
|
actualModelProvider: task.actual_model_provider ?? null,
|
|
595
730
|
actualModel: task.actual_model ?? null,
|
|
731
|
+
workerId: task.worker_id ?? task.workerId ?? null,
|
|
732
|
+
workerLabel: task.worker_label ?? task.workerLabel ?? null,
|
|
733
|
+
workerOccupationEmoji: task.worker_occupation_emoji ??
|
|
734
|
+
task.workerOccupationEmoji ?? null,
|
|
735
|
+
workerStatus: task.worker_status ?? task.workerStatus ?? null,
|
|
736
|
+
tokenUsage: projectAgentTokenUsage(task.token_usage ?? task.tokenUsage),
|
|
737
|
+
...(hasAny(task, ['worker_runtime', 'workerRuntime']) ? {
|
|
738
|
+
workerRuntime: projectAgentWorkerRuntime(task.worker_runtime ?? task.workerRuntime)
|
|
739
|
+
} : {}),
|
|
596
740
|
executionSummary: projectAgentExecutionSummary(
|
|
597
741
|
task.execution_summary ?? task.executionSummary
|
|
598
742
|
),
|
|
@@ -608,7 +752,12 @@ export function projectAgentRecruitmentPolicyRecord(value = {}) {
|
|
|
608
752
|
return {
|
|
609
753
|
personalSpaceId: value.personal_space_id,
|
|
610
754
|
confirmationMode: value.confirmation_mode ?? 'automatic',
|
|
611
|
-
updatedAt: value.updated_at ?? null
|
|
755
|
+
updatedAt: value.updated_at ?? null,
|
|
756
|
+
...(value.policy_status ? {
|
|
757
|
+
policyStatus: value.policy_status,
|
|
758
|
+
appliesToRecruitment: value.applies_to_recruitment,
|
|
759
|
+
warning: value.warning
|
|
760
|
+
} : {})
|
|
612
761
|
};
|
|
613
762
|
}
|
|
614
763
|
|
|
@@ -991,6 +1140,7 @@ export function routingLearningRecord(value = {}) {
|
|
|
991
1140
|
ratingCount: value.rating_count,
|
|
992
1141
|
averageRating: value.average_rating,
|
|
993
1142
|
neutralDueToInsufficientEvidence: value.neutral_due_to_insufficient_evidence,
|
|
1143
|
+
validationWarnings: value.validation_warnings,
|
|
994
1144
|
weightedSuccess: value.weighted_success,
|
|
995
1145
|
weightedFailure: value.weighted_failure,
|
|
996
1146
|
evidenceRefs: value.evidence_refs,
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { ApplicationError, ApplicationErrorCode } from '../app/application-error.js';
|
|
2
|
+
import { detectSensitiveContent } from '../security/sensitive-content.js';
|
|
3
|
+
|
|
4
|
+
export function agentMemoryRecord(value) {
|
|
5
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) ||
|
|
6
|
+
!Number.isInteger(value.revision) || value.revision < 1 ||
|
|
7
|
+
!value.memory || typeof value.memory !== 'object' || Array.isArray(value.memory) ||
|
|
8
|
+
typeof value.memory.summary !== 'string') {
|
|
9
|
+
throw invalidAgentMemoryResponse();
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
checkpointId: value.checkpoint_id,
|
|
13
|
+
personalSpaceId: value.personal_space_id,
|
|
14
|
+
personalProjectId: value.personal_project_id,
|
|
15
|
+
agentId: value.agent_id,
|
|
16
|
+
revision: value.revision,
|
|
17
|
+
memory: {
|
|
18
|
+
summary: value.memory.summary,
|
|
19
|
+
decisions: memoryNotes(value.memory.decisions),
|
|
20
|
+
openThreads: memoryNotes(value.memory.open_threads),
|
|
21
|
+
nextActions: memoryNotes(value.memory.next_actions)
|
|
22
|
+
},
|
|
23
|
+
sourceApplication: value.source_application,
|
|
24
|
+
sourceSessionId: value.source_session_id ?? null,
|
|
25
|
+
taskId: value.task_id ?? null,
|
|
26
|
+
createdAt: value.created_at
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function agentMemoryView(value) {
|
|
31
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) ||
|
|
32
|
+
!Number.isInteger(value.revision) || value.revision < 0 ||
|
|
33
|
+
(value.history !== undefined && value.history !== null && !Array.isArray(value.history))) {
|
|
34
|
+
throw invalidAgentMemoryResponse();
|
|
35
|
+
}
|
|
36
|
+
const current = value.current === undefined || value.current === null
|
|
37
|
+
? null : agentMemoryRecord(value.current);
|
|
38
|
+
const history = (value.history ?? []).map(agentMemoryRecord)
|
|
39
|
+
.filter(record => record.revision !== current?.revision);
|
|
40
|
+
return {
|
|
41
|
+
personalSpaceId: value.personal_space_id,
|
|
42
|
+
personalProjectId: value.personal_project_id,
|
|
43
|
+
agentId: value.agent_id,
|
|
44
|
+
scope: value.scope,
|
|
45
|
+
storage: value.storage,
|
|
46
|
+
authority: value.authority,
|
|
47
|
+
revision: value.revision ?? 0,
|
|
48
|
+
current,
|
|
49
|
+
history
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function getProjectAgentMemory(application, input) {
|
|
54
|
+
await requireAgentMemoryAccess(application, input);
|
|
55
|
+
return agentMemoryView(await application.personal.getProjectAgentMemory(input));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function checkpointProjectAgentMemory(application, input) {
|
|
59
|
+
const prepared = await prepareProjectAgentMemory(application, input);
|
|
60
|
+
if (prepared.status === 'capture_disabled') return prepared;
|
|
61
|
+
const value = await application.personal.writeProjectAgentMemory(prepared.request);
|
|
62
|
+
return { status: 'checkpointed', ...agentMemoryRecord(value) };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Validate and normalize through the same boundary without performing a write.
|
|
66
|
+
// Task checkpoints send this payload to the Provider's atomic prepare operation.
|
|
67
|
+
export async function prepareProjectAgentMemory(application, input) {
|
|
68
|
+
if (detectSensitiveContent(JSON.stringify(input.memory)).restricted) {
|
|
69
|
+
throw new ApplicationError(ApplicationErrorCode.VALIDATION, 'Agent working memory contains credentials');
|
|
70
|
+
}
|
|
71
|
+
await requireAgentMemoryAccess(application, input);
|
|
72
|
+
const policy = application.getCapturePolicy?.() ?? { enabled: true };
|
|
73
|
+
if (!policy.enabled) return { status: 'capture_disabled', capturePolicy: policy };
|
|
74
|
+
return { request: {
|
|
75
|
+
personal_space_id: input.personalSpaceId,
|
|
76
|
+
personal_project_id: input.personalProjectId,
|
|
77
|
+
agent_id: input.agentId,
|
|
78
|
+
expected_revision: input.expectedRevision,
|
|
79
|
+
idempotency_key: input.idempotencyKey,
|
|
80
|
+
memory: {
|
|
81
|
+
summary: input.memory.summary,
|
|
82
|
+
decisions: input.memory.decisions ?? [],
|
|
83
|
+
open_threads: input.memory.openThreads ?? [],
|
|
84
|
+
next_actions: input.memory.nextActions ?? []
|
|
85
|
+
},
|
|
86
|
+
source_application: input.sourceApplication ?? 'other',
|
|
87
|
+
source_session_id: input.sourceSessionId ?? null,
|
|
88
|
+
task_id: input.taskId ?? null
|
|
89
|
+
} };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function requireAgentMemoryAccess(application, input) {
|
|
93
|
+
const agent = await application.getProjectAgent(input);
|
|
94
|
+
if (agent.profile.status !== 'active' || agent.memoryScope !== 'reviewed_agent') {
|
|
95
|
+
throw new ApplicationError(ApplicationErrorCode.VALIDATION, 'An active durable Agent assignment is required for working memory');
|
|
96
|
+
}
|
|
97
|
+
if (!(agent.profile.allowedClients ?? []).includes(input.sourceApplication ?? 'other')) {
|
|
98
|
+
throw new ApplicationError(ApplicationErrorCode.VALIDATION, 'This client is not allowed to load the Agent memory');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function memoryNotes(value) {
|
|
103
|
+
const notes = value ?? [];
|
|
104
|
+
if (!Array.isArray(notes) || notes.some(note => typeof note !== 'string')) {
|
|
105
|
+
throw invalidAgentMemoryResponse();
|
|
106
|
+
}
|
|
107
|
+
return [...notes];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function invalidAgentMemoryResponse() {
|
|
111
|
+
return new ApplicationError(
|
|
112
|
+
ApplicationErrorCode.VALIDATION,
|
|
113
|
+
'Provider returned an invalid Agent memory record'
|
|
114
|
+
);
|
|
115
|
+
}
|