fuli-context 0.7.6 → 0.7.8
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-9CVX91tr.js} +1 -1
- package/dist/web/assets/{ConnectionsPage-BWn4ywGJ.js → ConnectionsPage-CWbCVFdv.js} +1 -1
- package/dist/web/assets/EmployeeRecruitDialog-CQgNpGJ_.js +1 -0
- package/dist/web/assets/EmployeeRecruitDialog-CfFlyKSh.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-CWg4WJhr.css +1 -0
- package/dist/web/assets/EmployeeWorkbenchPage-CwU4qBgD.js +1 -0
- package/dist/web/assets/KnowledgeEditDialog-B6TGAcFH.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-M2pLY0bR.js} +1 -1
- package/dist/web/assets/{KnowledgeOrganizerPage-Dfj3vIpU.js → KnowledgeOrganizerPage-DzeAlk9b.js} +1 -1
- package/dist/web/assets/KnowledgePage-BJu9w0fF.js +1 -0
- package/dist/web/assets/{KnowledgeWorkspace-ChEB5Bwk.js → KnowledgeWorkspace-CCt8rnBb.js} +1 -1
- package/dist/web/assets/{OverviewPage-Cd66M0RT.js → OverviewPage-CZswVqui.js} +1 -1
- package/dist/web/assets/{PersonalProfilePage-RCFHL0Wz.js → PersonalProfilePage-f1nSF6kx.js} +1 -1
- package/dist/web/assets/PersonalProjectsPage-D__eJf0t.js +1 -0
- package/dist/web/assets/ProjectAgentsPage-C3vW6wmk.css +1 -0
- package/dist/web/assets/ProjectAgentsPage-LrwagMGj.js +11 -0
- package/dist/web/assets/{PublicProjectsPage-mstPEjHe.js → PublicProjectsPage-BdC2Qk4n.js} +1 -1
- package/dist/web/assets/{ReviewPage-6Y1SmfZy.js → ReviewPage-Cbgl8_Si.js} +1 -1
- package/dist/web/assets/SearchableSelect-ERm-k4KI.js +1 -0
- package/dist/web/assets/{SettingsPage--LdTMUm7.js → SettingsPage-DWso4x29.js} +1 -1
- package/dist/web/assets/{WritingTastePage-CIpKswvs.js → WritingTastePage-CFpCjmIY.js} +1 -1
- package/dist/web/assets/catalog-WGLn7ERJ.js +1 -0
- package/dist/web/assets/{console-BT1P2Db4.js → console-DQgu0JIA.js} +1 -1
- package/dist/web/assets/conversation-launcher-settings-0KtlG_LV.js +1 -0
- package/dist/web/assets/{i18n-js6gfc7j.js → i18n-ByRiA3pJ.js} +3 -3
- package/dist/web/assets/{identity-CfDfanpa.js → identity-CxdPRMwH.js} +1 -1
- package/dist/web/assets/index-JAZe6lfX.js +2 -0
- package/dist/web/assets/index-wcXzzggp.css +1 -0
- package/dist/web/assets/{model-DJkLAJsg.js → model-Db4-KefQ.js} +1 -1
- package/dist/web/assets/{useApi-CROJJdhE-BdSti7Y2.js → useApi-CROJJdhE-CePMjc08.js} +1 -1
- package/dist/web/assets/{vue-router-Kk67EaCP.js → vue-router-CzX-hn3P.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/update-command.js +6 -43
- 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 +30 -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/semantic-version.js +42 -0
- 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/src/system/package-version-checker.js +72 -0
- package/src/system/system-service.js +3 -0
- 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
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Literal
|
|
3
|
+
|
|
4
|
+
from pydantic import Field, model_validator
|
|
5
|
+
|
|
6
|
+
from .model_base import StrictModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
KnowledgeItemKind = Literal['entity', 'relationship']
|
|
10
|
+
KnowledgeOperationActor = Literal['human', 'agent']
|
|
11
|
+
HumanChangeStatus = Literal['none', 'unseen', 'viewed', 'reviewed']
|
|
12
|
+
KnowledgeAuditAction = Literal[
|
|
13
|
+
'human_change',
|
|
14
|
+
'agent_view',
|
|
15
|
+
'agent_review',
|
|
16
|
+
'knowledge_used',
|
|
17
|
+
'knowledge_feedback',
|
|
18
|
+
]
|
|
19
|
+
KnowledgeUseKind = Literal['cited', 'applied']
|
|
20
|
+
KnowledgeFeedbackKind = Literal[
|
|
21
|
+
'rejected',
|
|
22
|
+
'validation_failed',
|
|
23
|
+
'contradicted',
|
|
24
|
+
'outdated',
|
|
25
|
+
]
|
|
26
|
+
KnowledgeRevisionAction = Literal[
|
|
27
|
+
'confirm',
|
|
28
|
+
'update',
|
|
29
|
+
'invalidate',
|
|
30
|
+
'link_replacement',
|
|
31
|
+
'restore',
|
|
32
|
+
'scope_change',
|
|
33
|
+
'batch_confirm',
|
|
34
|
+
'promote_common',
|
|
35
|
+
'replace_common_duplicate',
|
|
36
|
+
]
|
|
37
|
+
PreferenceScope = Literal['global', 'project']
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class KnowledgeAssignmentChange(StrictModel):
|
|
41
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
42
|
+
item_kind: KnowledgeItemKind
|
|
43
|
+
target_project_id: str = Field(min_length=1, max_length=128)
|
|
44
|
+
reason: str = Field(min_length=1, max_length=2000)
|
|
45
|
+
operation_actor: KnowledgeOperationActor = 'agent'
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PreferenceScopeChange(StrictModel):
|
|
49
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
50
|
+
item_kind: KnowledgeItemKind
|
|
51
|
+
scope: PreferenceScope
|
|
52
|
+
project_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
53
|
+
reason: str = Field(min_length=1, max_length=2000)
|
|
54
|
+
operation_actor: KnowledgeOperationActor = 'agent'
|
|
55
|
+
|
|
56
|
+
@model_validator(mode='after')
|
|
57
|
+
def validate_project_scope(self):
|
|
58
|
+
if self.scope == 'project' and not self.project_id:
|
|
59
|
+
raise ValueError('project_id is required for project preference scope')
|
|
60
|
+
if self.scope == 'global' and self.project_id:
|
|
61
|
+
raise ValueError('project_id is only valid for project preference scope')
|
|
62
|
+
return self
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class KnowledgeRevisionRecord(StrictModel):
|
|
66
|
+
id: str
|
|
67
|
+
item_id: str
|
|
68
|
+
item_kind: KnowledgeItemKind
|
|
69
|
+
action: KnowledgeRevisionAction
|
|
70
|
+
reason: str
|
|
71
|
+
previous: dict[str, Any] = Field(default_factory=dict)
|
|
72
|
+
current: dict[str, Any] = Field(default_factory=dict)
|
|
73
|
+
created_at: datetime
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class KnowledgeAuditRecord(StrictModel):
|
|
77
|
+
id: str
|
|
78
|
+
item_id: str
|
|
79
|
+
item_kind: KnowledgeItemKind
|
|
80
|
+
action: KnowledgeAuditAction
|
|
81
|
+
human_change_version: int = Field(default=0, ge=0)
|
|
82
|
+
reason: str
|
|
83
|
+
tool_name: str | None = None
|
|
84
|
+
task_id: str | None = None
|
|
85
|
+
session_id: str | None = None
|
|
86
|
+
use_kind: KnowledgeUseKind | None = None
|
|
87
|
+
feedback_kind: KnowledgeFeedbackKind | None = None
|
|
88
|
+
reported_by_kind: Literal[
|
|
89
|
+
'user',
|
|
90
|
+
'agent',
|
|
91
|
+
'authoritative_source',
|
|
92
|
+
] | None = None
|
|
93
|
+
evidence_summary: str | None = None
|
|
94
|
+
source_uri: str | None = None
|
|
95
|
+
usage_generation: int | None = Field(default=None, ge=1)
|
|
96
|
+
conflict_check: Literal['no_conflict', 'conflict'] | None = None
|
|
97
|
+
classification_check: Literal['reasonable', 'needs_change'] | None = None
|
|
98
|
+
outcome: Literal[
|
|
99
|
+
'pending_review',
|
|
100
|
+
'requires_attention',
|
|
101
|
+
'reviewed',
|
|
102
|
+
'agent_confirmed',
|
|
103
|
+
] | None = None
|
|
104
|
+
created_at: datetime
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class KnowledgeAgentViewItem(StrictModel):
|
|
108
|
+
item_id: str = Field(min_length=1, max_length=256)
|
|
109
|
+
item_kind: KnowledgeItemKind
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class KnowledgeAgentViewCreate(StrictModel):
|
|
113
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
114
|
+
tool_name: str = Field(min_length=1, max_length=128)
|
|
115
|
+
items: list[KnowledgeAgentViewItem] = Field(max_length=200)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class KnowledgeAgentViewResult(StrictModel):
|
|
119
|
+
recorded_count: int = Field(ge=0, le=200)
|
|
120
|
+
item_keys: list[str] = Field(max_length=200)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class KnowledgeAgentReviewCreate(StrictModel):
|
|
124
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
125
|
+
item_kind: KnowledgeItemKind
|
|
126
|
+
human_change_version: int = Field(ge=1)
|
|
127
|
+
conflict_check: Literal['no_conflict', 'conflict']
|
|
128
|
+
classification_check: Literal['reasonable', 'needs_change']
|
|
129
|
+
note: str = Field(min_length=1, max_length=2000)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class KnowledgeHumanChangeSearchRequest(StrictModel):
|
|
133
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
134
|
+
query: str = Field(default='', max_length=2048)
|
|
135
|
+
status: Literal[
|
|
136
|
+
'all',
|
|
137
|
+
'human_changed',
|
|
138
|
+
'unseen',
|
|
139
|
+
'viewed',
|
|
140
|
+
'reviewed',
|
|
141
|
+
] = 'all'
|
|
142
|
+
limit: int = Field(default=50, ge=1, le=200)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class KnowledgeHumanChangeItem(StrictModel):
|
|
146
|
+
item_id: str
|
|
147
|
+
item_kind: KnowledgeItemKind
|
|
148
|
+
title: str
|
|
149
|
+
body: str
|
|
150
|
+
type: str
|
|
151
|
+
human_change_status: HumanChangeStatus
|
|
152
|
+
human_change_version: int = Field(ge=1)
|
|
153
|
+
last_human_changed_at: datetime
|
|
154
|
+
last_agent_viewed_at: datetime | None = None
|
|
155
|
+
last_agent_reviewed_at: datetime | None = None
|
|
156
|
+
audit_events: list[KnowledgeAuditRecord] = Field(default_factory=list)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class KnowledgeHumanChangeSearchResult(StrictModel):
|
|
160
|
+
items: list[KnowledgeHumanChangeItem] = Field(default_factory=list)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class KnowledgeAssignmentRecord(StrictModel):
|
|
164
|
+
id: str
|
|
165
|
+
item_id: str
|
|
166
|
+
item_kind: KnowledgeItemKind
|
|
167
|
+
project_id: str
|
|
168
|
+
previous_project_id: str | None = None
|
|
169
|
+
reason: str
|
|
170
|
+
created_at: datetime
|
|
171
|
+
updated_at: datetime
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import re
|
|
3
3
|
from typing import Any
|
|
4
|
+
from urllib.parse import urlsplit
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
_CREDENTIAL_PATTERNS = (
|
|
@@ -162,6 +163,37 @@ def normalize_provider_url(value: str) -> str:
|
|
|
162
163
|
return value.rstrip('/')
|
|
163
164
|
|
|
164
165
|
|
|
166
|
+
def normalize_source_session_url(value: str | None) -> str | None:
|
|
167
|
+
"""Allow auditable session links without accepting credential-bearing URLs."""
|
|
168
|
+
|
|
169
|
+
if value is None:
|
|
170
|
+
return None
|
|
171
|
+
normalized = value.strip()
|
|
172
|
+
parsed = urlsplit(normalized)
|
|
173
|
+
is_codex_thread = (
|
|
174
|
+
parsed.scheme == 'codex'
|
|
175
|
+
and parsed.netloc == 'threads'
|
|
176
|
+
and bool(parsed.path.strip('/'))
|
|
177
|
+
)
|
|
178
|
+
is_https = parsed.scheme == 'https' and bool(parsed.netloc)
|
|
179
|
+
is_loopback_http = (
|
|
180
|
+
parsed.scheme == 'http'
|
|
181
|
+
and parsed.hostname in {'127.0.0.1', 'localhost', '::1'}
|
|
182
|
+
)
|
|
183
|
+
if (
|
|
184
|
+
not normalized
|
|
185
|
+
or parsed.username
|
|
186
|
+
or parsed.password
|
|
187
|
+
or parsed.query
|
|
188
|
+
or parsed.fragment
|
|
189
|
+
or not (is_codex_thread or is_https or is_loopback_http)
|
|
190
|
+
):
|
|
191
|
+
raise ValueError(
|
|
192
|
+
'source session URL must be a Codex thread, HTTPS, or loopback URL'
|
|
193
|
+
)
|
|
194
|
+
return normalized
|
|
195
|
+
|
|
196
|
+
|
|
165
197
|
def complete_epistemic_state(
|
|
166
198
|
*,
|
|
167
199
|
origin_quadrant: str,
|
|
@@ -4,13 +4,34 @@ from urllib.parse import urlsplit
|
|
|
4
4
|
|
|
5
5
|
from pydantic import (
|
|
6
6
|
AliasChoices,
|
|
7
|
-
BaseModel,
|
|
8
|
-
ConfigDict,
|
|
9
7
|
Field,
|
|
10
8
|
field_validator,
|
|
11
9
|
model_validator,
|
|
12
10
|
)
|
|
13
11
|
|
|
12
|
+
from .knowledge_audit_models import (
|
|
13
|
+
HumanChangeStatus,
|
|
14
|
+
KnowledgeAgentReviewCreate,
|
|
15
|
+
KnowledgeAgentViewCreate,
|
|
16
|
+
KnowledgeAgentViewItem,
|
|
17
|
+
KnowledgeAgentViewResult,
|
|
18
|
+
KnowledgeAssignmentChange,
|
|
19
|
+
KnowledgeAssignmentRecord,
|
|
20
|
+
KnowledgeAuditAction,
|
|
21
|
+
KnowledgeAuditRecord,
|
|
22
|
+
KnowledgeFeedbackKind,
|
|
23
|
+
KnowledgeHumanChangeItem,
|
|
24
|
+
KnowledgeHumanChangeSearchRequest,
|
|
25
|
+
KnowledgeHumanChangeSearchResult,
|
|
26
|
+
KnowledgeItemKind,
|
|
27
|
+
KnowledgeOperationActor,
|
|
28
|
+
KnowledgeRevisionAction,
|
|
29
|
+
KnowledgeRevisionRecord,
|
|
30
|
+
KnowledgeUseKind,
|
|
31
|
+
PreferenceScope,
|
|
32
|
+
PreferenceScopeChange,
|
|
33
|
+
)
|
|
34
|
+
from .model_base import StrictModel
|
|
14
35
|
from .model_validation import (
|
|
15
36
|
complete_epistemic_state,
|
|
16
37
|
normalize_provider_url,
|
|
@@ -52,39 +73,11 @@ ProjectRelationType = Literal[
|
|
|
52
73
|
'RELATED_TO',
|
|
53
74
|
]
|
|
54
75
|
ProjectRelationStatus = Literal['pending', 'active', 'rejected']
|
|
55
|
-
KnowledgeItemKind = Literal['entity', 'relationship']
|
|
56
|
-
KnowledgeOperationActor = Literal['human', 'agent']
|
|
57
|
-
HumanChangeStatus = Literal['none', 'unseen', 'viewed', 'reviewed']
|
|
58
|
-
KnowledgeAuditAction = Literal[
|
|
59
|
-
'human_change',
|
|
60
|
-
'agent_view',
|
|
61
|
-
'agent_review',
|
|
62
|
-
'knowledge_used',
|
|
63
|
-
'knowledge_feedback',
|
|
64
|
-
]
|
|
65
|
-
KnowledgeUseKind = Literal['cited', 'applied']
|
|
66
|
-
KnowledgeFeedbackKind = Literal[
|
|
67
|
-
'rejected',
|
|
68
|
-
'validation_failed',
|
|
69
|
-
'contradicted',
|
|
70
|
-
'outdated',
|
|
71
|
-
]
|
|
72
76
|
KnowledgeInheritanceMode = Literal[
|
|
73
77
|
'local_only',
|
|
74
78
|
'descendants',
|
|
75
79
|
'selected_projects',
|
|
76
80
|
]
|
|
77
|
-
KnowledgeRevisionAction = Literal[
|
|
78
|
-
'confirm',
|
|
79
|
-
'update',
|
|
80
|
-
'invalidate',
|
|
81
|
-
'link_replacement',
|
|
82
|
-
'restore',
|
|
83
|
-
'scope_change',
|
|
84
|
-
'batch_confirm',
|
|
85
|
-
'promote_common',
|
|
86
|
-
'replace_common_duplicate',
|
|
87
|
-
]
|
|
88
81
|
KnowledgeContentRevisionAction = Literal[
|
|
89
82
|
'confirm',
|
|
90
83
|
'update',
|
|
@@ -103,7 +96,6 @@ EpistemicStatus = Literal['confirmed', 'observed', 'exploratory']
|
|
|
103
96
|
ConfirmationStatus = Literal['confirmed', 'agent_confirmed', 'pending']
|
|
104
97
|
ConfirmationActorKind = Literal['user', 'agent', 'authoritative_source', 'import']
|
|
105
98
|
PersonalProfileAspect = Literal['taste', 'personality', 'judgment_preference']
|
|
106
|
-
PreferenceScope = Literal['global', 'project']
|
|
107
99
|
ScopedPreferenceScope = Literal['global', 'project', 'agent']
|
|
108
100
|
PreferenceConflictQueueStatus = Literal['ai_pending', 'resolved']
|
|
109
101
|
PreferenceConflictResolutionAction = Literal[
|
|
@@ -112,11 +104,9 @@ PreferenceConflictResolutionAction = Literal[
|
|
|
112
104
|
'keep_right',
|
|
113
105
|
'split_scope',
|
|
114
106
|
]
|
|
115
|
-
SourceApplication = Literal[
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
class StrictModel(BaseModel):
|
|
119
|
-
model_config = ConfigDict(extra='forbid', str_strip_whitespace=True)
|
|
107
|
+
SourceApplication = Literal[
|
|
108
|
+
'codex', 'claude', 'claude_code', 'cursor', 'kiro', 'other'
|
|
109
|
+
]
|
|
120
110
|
|
|
121
111
|
|
|
122
112
|
def _validated_source_uri(value: str) -> str:
|
|
@@ -1163,137 +1153,3 @@ class KnowledgeBatchConfirmationResult(StrictModel):
|
|
|
1163
1153
|
confirmed_count: int = Field(ge=0, le=200)
|
|
1164
1154
|
confirmed_at: datetime
|
|
1165
1155
|
item_keys: list[str] = Field(max_length=200)
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
class KnowledgeAssignmentChange(StrictModel):
|
|
1169
|
-
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
1170
|
-
item_kind: KnowledgeItemKind
|
|
1171
|
-
target_project_id: str = Field(min_length=1, max_length=128)
|
|
1172
|
-
reason: str = Field(min_length=1, max_length=2000)
|
|
1173
|
-
operation_actor: KnowledgeOperationActor = 'agent'
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
class PreferenceScopeChange(StrictModel):
|
|
1177
|
-
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
1178
|
-
item_kind: KnowledgeItemKind
|
|
1179
|
-
scope: PreferenceScope
|
|
1180
|
-
project_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
1181
|
-
reason: str = Field(min_length=1, max_length=2000)
|
|
1182
|
-
operation_actor: KnowledgeOperationActor = 'agent'
|
|
1183
|
-
|
|
1184
|
-
@model_validator(mode='after')
|
|
1185
|
-
def validate_project_scope(self):
|
|
1186
|
-
if self.scope == 'project' and not self.project_id:
|
|
1187
|
-
raise ValueError('project_id is required for project preference scope')
|
|
1188
|
-
if self.scope == 'global' and self.project_id:
|
|
1189
|
-
raise ValueError('project_id is only valid for project preference scope')
|
|
1190
|
-
return self
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
class KnowledgeRevisionRecord(StrictModel):
|
|
1194
|
-
id: str
|
|
1195
|
-
item_id: str
|
|
1196
|
-
item_kind: KnowledgeItemKind
|
|
1197
|
-
action: KnowledgeRevisionAction
|
|
1198
|
-
reason: str
|
|
1199
|
-
previous: dict[str, Any] = Field(default_factory=dict)
|
|
1200
|
-
current: dict[str, Any] = Field(default_factory=dict)
|
|
1201
|
-
created_at: datetime
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
class KnowledgeAuditRecord(StrictModel):
|
|
1205
|
-
id: str
|
|
1206
|
-
item_id: str
|
|
1207
|
-
item_kind: KnowledgeItemKind
|
|
1208
|
-
action: KnowledgeAuditAction
|
|
1209
|
-
human_change_version: int = Field(default=0, ge=0)
|
|
1210
|
-
reason: str
|
|
1211
|
-
tool_name: str | None = None
|
|
1212
|
-
task_id: str | None = None
|
|
1213
|
-
session_id: str | None = None
|
|
1214
|
-
use_kind: KnowledgeUseKind | None = None
|
|
1215
|
-
feedback_kind: KnowledgeFeedbackKind | None = None
|
|
1216
|
-
reported_by_kind: Literal[
|
|
1217
|
-
'user',
|
|
1218
|
-
'agent',
|
|
1219
|
-
'authoritative_source',
|
|
1220
|
-
] | None = None
|
|
1221
|
-
evidence_summary: str | None = None
|
|
1222
|
-
source_uri: str | None = None
|
|
1223
|
-
usage_generation: int | None = Field(default=None, ge=1)
|
|
1224
|
-
conflict_check: Literal['no_conflict', 'conflict'] | None = None
|
|
1225
|
-
classification_check: Literal['reasonable', 'needs_change'] | None = None
|
|
1226
|
-
outcome: Literal[
|
|
1227
|
-
'pending_review',
|
|
1228
|
-
'requires_attention',
|
|
1229
|
-
'reviewed',
|
|
1230
|
-
'agent_confirmed',
|
|
1231
|
-
] | None = None
|
|
1232
|
-
created_at: datetime
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
class KnowledgeAgentViewItem(StrictModel):
|
|
1236
|
-
item_id: str = Field(min_length=1, max_length=256)
|
|
1237
|
-
item_kind: KnowledgeItemKind
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
class KnowledgeAgentViewCreate(StrictModel):
|
|
1241
|
-
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
1242
|
-
tool_name: str = Field(min_length=1, max_length=128)
|
|
1243
|
-
items: list[KnowledgeAgentViewItem] = Field(max_length=200)
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
class KnowledgeAgentViewResult(StrictModel):
|
|
1247
|
-
recorded_count: int = Field(ge=0, le=200)
|
|
1248
|
-
item_keys: list[str] = Field(max_length=200)
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
class KnowledgeAgentReviewCreate(StrictModel):
|
|
1252
|
-
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
1253
|
-
item_kind: KnowledgeItemKind
|
|
1254
|
-
human_change_version: int = Field(ge=1)
|
|
1255
|
-
conflict_check: Literal['no_conflict', 'conflict']
|
|
1256
|
-
classification_check: Literal['reasonable', 'needs_change']
|
|
1257
|
-
note: str = Field(min_length=1, max_length=2000)
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
class KnowledgeHumanChangeSearchRequest(StrictModel):
|
|
1261
|
-
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
1262
|
-
query: str = Field(default='', max_length=2048)
|
|
1263
|
-
status: Literal[
|
|
1264
|
-
'all',
|
|
1265
|
-
'human_changed',
|
|
1266
|
-
'unseen',
|
|
1267
|
-
'viewed',
|
|
1268
|
-
'reviewed',
|
|
1269
|
-
] = 'all'
|
|
1270
|
-
limit: int = Field(default=50, ge=1, le=200)
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
class KnowledgeHumanChangeItem(StrictModel):
|
|
1274
|
-
item_id: str
|
|
1275
|
-
item_kind: KnowledgeItemKind
|
|
1276
|
-
title: str
|
|
1277
|
-
body: str
|
|
1278
|
-
type: str
|
|
1279
|
-
human_change_status: HumanChangeStatus
|
|
1280
|
-
human_change_version: int = Field(ge=1)
|
|
1281
|
-
last_human_changed_at: datetime
|
|
1282
|
-
last_agent_viewed_at: datetime | None = None
|
|
1283
|
-
last_agent_reviewed_at: datetime | None = None
|
|
1284
|
-
audit_events: list[KnowledgeAuditRecord] = Field(default_factory=list)
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
class KnowledgeHumanChangeSearchResult(StrictModel):
|
|
1288
|
-
items: list[KnowledgeHumanChangeItem] = Field(default_factory=list)
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
class KnowledgeAssignmentRecord(StrictModel):
|
|
1292
|
-
id: str
|
|
1293
|
-
item_id: str
|
|
1294
|
-
item_kind: KnowledgeItemKind
|
|
1295
|
-
project_id: str
|
|
1296
|
-
previous_project_id: str | None = None
|
|
1297
|
-
reason: str
|
|
1298
|
-
created_at: datetime
|
|
1299
|
-
updated_at: datetime
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Read-only task-entry selection; never submits a task or spawns a worker."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
from .models import SourceApplication, StrictModel
|
|
8
|
+
from .project_agent_memory_models import MemoryNote
|
|
9
|
+
from .project_agent_models import ProjectAgentRecord
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ProjectAgentContextRequest(StrictModel):
|
|
13
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
14
|
+
personal_project_id: str = Field(min_length=1, max_length=128)
|
|
15
|
+
agent_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
16
|
+
session_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
17
|
+
turn_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
18
|
+
work_kind: str = Field(default='project_context', min_length=1, max_length=128)
|
|
19
|
+
required_capabilities: list[MemoryNote] = Field(default_factory=list, max_length=16)
|
|
20
|
+
source_application: SourceApplication = 'other'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ProjectAgentContextResolution(StrictModel):
|
|
24
|
+
status: Literal['ready', 'manual_selection', 'unassigned', 'agent_unavailable']
|
|
25
|
+
reason: str
|
|
26
|
+
match_basis: list[str] = Field(default_factory=list)
|
|
27
|
+
candidate_count: int = 0
|
|
28
|
+
agent: ProjectAgentRecord | None = None
|
|
29
|
+
worker_started: Literal[False] = False
|
|
@@ -11,7 +11,7 @@ import json
|
|
|
11
11
|
from datetime import datetime
|
|
12
12
|
from typing import Literal
|
|
13
13
|
|
|
14
|
-
from pydantic import Field, field_validator, model_validator
|
|
14
|
+
from pydantic import AwareDatetime, Field, field_validator, model_validator
|
|
15
15
|
|
|
16
16
|
from .model_validation import reject_credentials
|
|
17
17
|
from .models import SourceApplication, StrictModel
|
|
@@ -81,6 +81,26 @@ ProjectAgentExecutorTerminalOutcome = Literal[
|
|
|
81
81
|
'cancelled',
|
|
82
82
|
]
|
|
83
83
|
|
|
84
|
+
_CAPABILITY_ALIASES = {
|
|
85
|
+
'code': 'coding',
|
|
86
|
+
'development': 'coding',
|
|
87
|
+
'implementation': 'coding',
|
|
88
|
+
'software_development': 'coding',
|
|
89
|
+
'software_implementation': 'coding',
|
|
90
|
+
'test': 'testing',
|
|
91
|
+
'tests': 'testing',
|
|
92
|
+
'run_test': 'testing',
|
|
93
|
+
'run_tests': 'testing',
|
|
94
|
+
'test_execution': 'testing',
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def project_agent_capability_key(value: str) -> str:
|
|
99
|
+
"""Return one provider-neutral key for common capability vocabulary."""
|
|
100
|
+
|
|
101
|
+
key = '_'.join(value.casefold().replace('-', ' ').split())
|
|
102
|
+
return _CAPABILITY_ALIASES.get(key, key)
|
|
103
|
+
|
|
84
104
|
|
|
85
105
|
def project_agent_model_strategy_key(
|
|
86
106
|
strategy: ProjectAgentModelStrategy,
|
|
@@ -92,7 +112,10 @@ def project_agent_model_strategy_key(
|
|
|
92
112
|
# Canonicalizing them prevents equivalent provider-neutral strategies from
|
|
93
113
|
# creating separate evidence/aggregate buckets.
|
|
94
114
|
payload['capability_hints'] = sorted(
|
|
95
|
-
(
|
|
115
|
+
(
|
|
116
|
+
project_agent_capability_key(value)
|
|
117
|
+
for value in payload.get('capability_hints', [])
|
|
118
|
+
),
|
|
96
119
|
)
|
|
97
120
|
encoded = json.dumps(
|
|
98
121
|
payload,
|
|
@@ -210,7 +233,7 @@ class ProjectAgentExecutorPreflightReport(StrictModel):
|
|
|
210
233
|
max_length=64,
|
|
211
234
|
)
|
|
212
235
|
reason: str | None = Field(default=None, min_length=1, max_length=2048)
|
|
213
|
-
checked_at:
|
|
236
|
+
checked_at: AwareDatetime
|
|
214
237
|
idempotency_key: str = Field(min_length=8, max_length=256)
|
|
215
238
|
source_application: SourceApplication | None = None
|
|
216
239
|
source_session_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
@@ -238,7 +261,7 @@ class ProjectAgentExecutorHealthReport(StrictModel):
|
|
|
238
261
|
executor_id: str = Field(min_length=1, max_length=128)
|
|
239
262
|
status: ProjectAgentExecutorHealthStatus
|
|
240
263
|
reason: str | None = Field(default=None, min_length=1, max_length=2048)
|
|
241
|
-
checked_at:
|
|
264
|
+
checked_at: AwareDatetime
|
|
242
265
|
idempotency_key: str = Field(min_length=8, max_length=256)
|
|
243
266
|
source_application: SourceApplication | None = None
|
|
244
267
|
source_session_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
@@ -277,6 +300,7 @@ class ProjectAgentExecutorRecord(StrictModel):
|
|
|
277
300
|
|
|
278
301
|
|
|
279
302
|
class ProjectAgentExecutorPriorityUpdate(StrictModel):
|
|
303
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
280
304
|
executor_id: str = Field(min_length=1, max_length=128)
|
|
281
305
|
global_priority: int = Field(ge=1, le=1_000_000)
|
|
282
306
|
expected_revision: int = Field(ge=0)
|
|
@@ -453,7 +477,7 @@ class ProjectAgentExecutorActualReport(StrictModel):
|
|
|
453
477
|
matched_rule_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
454
478
|
fallback_reason: str | None = Field(default=None, min_length=1, max_length=2048)
|
|
455
479
|
idempotency_key: str = Field(min_length=8, max_length=256)
|
|
456
|
-
occurred_at:
|
|
480
|
+
occurred_at: AwareDatetime
|
|
457
481
|
source_application: SourceApplication | None = None
|
|
458
482
|
source_session_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
459
483
|
|
|
@@ -486,7 +510,7 @@ class ProjectAgentExecutorOutcomeEvidenceCreate(StrictModel):
|
|
|
486
510
|
reference_ids: list[str] = Field(default_factory=list, max_length=16)
|
|
487
511
|
note: str | None = Field(default=None, min_length=1, max_length=2048)
|
|
488
512
|
idempotency_key: str = Field(min_length=8, max_length=256)
|
|
489
|
-
occurred_at:
|
|
513
|
+
occurred_at: AwareDatetime
|
|
490
514
|
|
|
491
515
|
@field_validator('reference_ids')
|
|
492
516
|
@classmethod
|
|
@@ -537,6 +561,9 @@ class ProjectAgentExecutorOutcomeEvidenceRecord(
|
|
|
537
561
|
# contract keeps this optional for backwards-compatible callers; the store
|
|
538
562
|
# computes it before returning a durable record.
|
|
539
563
|
model_strategy_key: str = Field(min_length=64, max_length=64)
|
|
564
|
+
# Legacy unknown-timezone records remain inspectable/ignorable; new writes
|
|
565
|
+
# require an explicit offset and must not guess the caller's local zone.
|
|
566
|
+
occurred_at: datetime
|
|
540
567
|
evidence_id: str
|
|
541
568
|
ignored: bool = False
|
|
542
569
|
ignored_reason: str | None = None
|
|
@@ -579,6 +606,7 @@ class ProjectAgentExecutorOutcomeAggregate(StrictModel):
|
|
|
579
606
|
evidence_contributions: list[ProjectAgentExecutorEvidenceContribution] = Field(
|
|
580
607
|
default_factory=list
|
|
581
608
|
)
|
|
609
|
+
validation_warnings: list[str] = Field(default_factory=list)
|
|
582
610
|
|
|
583
611
|
@model_validator(mode='after')
|
|
584
612
|
def validate_strategy_key(self):
|
|
@@ -619,7 +647,7 @@ class ProjectAgentExecutorOutcomeReset(StrictModel):
|
|
|
619
647
|
)
|
|
620
648
|
reason: str = Field(min_length=1, max_length=2048)
|
|
621
649
|
idempotency_key: str = Field(min_length=8, max_length=256)
|
|
622
|
-
reset_at:
|
|
650
|
+
reset_at: AwareDatetime
|
|
623
651
|
|
|
624
652
|
@model_validator(mode='after')
|
|
625
653
|
def reject_sensitive_values(self):
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Provider-neutral contracts for private Agent working context.
|
|
2
|
+
|
|
3
|
+
Working notes are not confirmed project knowledge or user preferences. Their
|
|
4
|
+
scope and revision travel with every response, regardless of the calling host.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
import json
|
|
9
|
+
from typing import Annotated, Literal
|
|
10
|
+
|
|
11
|
+
from pydantic import Field, StringConstraints, model_validator
|
|
12
|
+
|
|
13
|
+
from .model_validation import reject_credentials
|
|
14
|
+
from .models import SourceApplication, StrictModel
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
MemoryNote = Annotated[
|
|
18
|
+
str, StringConstraints(strip_whitespace=True, min_length=1, max_length=1024)
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ProjectAgentWorkingMemory(StrictModel):
|
|
23
|
+
summary: Annotated[
|
|
24
|
+
str, StringConstraints(strip_whitespace=True, min_length=1, max_length=4000)
|
|
25
|
+
]
|
|
26
|
+
decisions: list[MemoryNote] = Field(default_factory=list, max_length=12)
|
|
27
|
+
open_threads: list[MemoryNote] = Field(default_factory=list, max_length=12)
|
|
28
|
+
next_actions: list[MemoryNote] = Field(default_factory=list, max_length=12)
|
|
29
|
+
|
|
30
|
+
@model_validator(mode='after')
|
|
31
|
+
def reject_sensitive_values(self):
|
|
32
|
+
reject_credentials(self, 'Agent working memory')
|
|
33
|
+
if len(json.dumps(self.model_dump(), ensure_ascii=False).encode()) > 32 * 1024:
|
|
34
|
+
raise ValueError('Agent working memory must fit within 32 KiB; distill the notes')
|
|
35
|
+
return self
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ProjectAgentMemoryWrite(StrictModel):
|
|
39
|
+
personal_space_id: str = Field(min_length=1, max_length=128)
|
|
40
|
+
personal_project_id: str = Field(min_length=1, max_length=128)
|
|
41
|
+
agent_id: str = Field(min_length=1, max_length=128)
|
|
42
|
+
expected_revision: int = Field(ge=0)
|
|
43
|
+
idempotency_key: str = Field(min_length=8, max_length=256)
|
|
44
|
+
memory: ProjectAgentWorkingMemory
|
|
45
|
+
source_application: SourceApplication
|
|
46
|
+
source_session_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
47
|
+
task_id: str | None = Field(default=None, min_length=1, max_length=128)
|
|
48
|
+
|
|
49
|
+
@model_validator(mode='after')
|
|
50
|
+
def reject_sensitive_values(self):
|
|
51
|
+
reject_credentials(self, 'Agent memory checkpoint')
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ProjectAgentMemoryRecord(StrictModel):
|
|
56
|
+
checkpoint_id: str
|
|
57
|
+
personal_space_id: str
|
|
58
|
+
personal_project_id: str
|
|
59
|
+
agent_id: str
|
|
60
|
+
revision: int = Field(ge=1)
|
|
61
|
+
memory: ProjectAgentWorkingMemory
|
|
62
|
+
source_application: SourceApplication
|
|
63
|
+
source_session_id: str | None = None
|
|
64
|
+
task_id: str | None = None
|
|
65
|
+
created_at: datetime
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ProjectAgentMemoryView(StrictModel):
|
|
69
|
+
personal_space_id: str
|
|
70
|
+
personal_project_id: str
|
|
71
|
+
agent_id: str
|
|
72
|
+
scope: Literal['private_agent_project'] = 'private_agent_project'
|
|
73
|
+
storage: Literal['neo4j'] = 'neo4j'
|
|
74
|
+
authority: Literal['working_context_not_confirmed_knowledge'] = (
|
|
75
|
+
'working_context_not_confirmed_knowledge'
|
|
76
|
+
)
|
|
77
|
+
revision: int = Field(default=0, ge=0)
|
|
78
|
+
current: ProjectAgentMemoryRecord | None = None
|
|
79
|
+
history: list[ProjectAgentMemoryRecord] = Field(default_factory=list)
|