Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ release tags and PEP 440 for the Python package.

## Unreleased

- Organizational Memory no longer equates different content in one Memory Type with contradiction.
Optional normalized subject keys enable scoped competing-record checks, exposed as UNKNOWN,
NO_COMPETING_RECORDS, or REVIEW_REQUIRED rather than a false confirmed conflict. Assessments use
all authorized active candidates before retrieval limits; supersession retains the subject and
retires the old version, including policy-authorized auto-acceptance. Legacy `conflict` is nullable;
use `conflict_status` instead. The bilingual Console supports subject keys for company notes.
Competing IDs are bounded to ten with an exact count/truncation marker, and serialized record
metadata is included in the retrieval-context estimate.
- Model execution rejects provider-reported truncated or incomplete responses before downstream
work can consume them. Token-limit failures show an actionable error; the managed LangGraph
runtime records them as known failures.
Expand Down
18 changes: 18 additions & 0 deletions alembic/versions/20260930_0057_memory_subject_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Add an optional explicit subject for conservative memory conflict assessment."""

import sqlalchemy as sa

from alembic import op

revision = "20260930_0057"
down_revision = "20260929_0056"
branch_labels = None
depends_on = None


def upgrade() -> None:
op.add_column("memory_records", sa.Column("subject_key", sa.String(128), nullable=True))


def downgrade() -> None:
op.drop_column("memory_records", "subject_key")
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ Exact search performs:
3. accepted/valid/expiry and sensitivity filtering;
4. pluggable ranking over only the already-authorized canonical candidate set;
5. count and approximate token-budget truncation;
6. conflict marking for unresolved memories of the same namespace/type;
6. conservative subject-scoped competing-record assessment (UNKNOWN without an explicit subject,
REVIEW_REQUIRED for different active contents sharing it, never inferred semantic contradiction);
7. immutable retrieval evidence.

Each `MemoryRetrieval` snapshots Policy ID/version, query digest, namespaces, requested types,
Expand Down
4 changes: 3 additions & 1 deletion docs/implementation-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ and non-critical single-team use. It is **not** a production HA or multi-tenant
| Collaboration and tools | Governed MCP registry/read tools/idempotent writes; trusted A2A peer registration, delegation, polling, cancellation, and unknown-outcome reconciliation | External providers/peers require configuration; irreversible writes and A2A streaming/push are not supported |
| External notifications | Optional Feishu bot cards for Task completion, failure, pending human review, and governed approval requests, backed by durable PostgreSQL delivery jobs | Gate is off by default; app credentials and a test group are required; inbound commands/approvals are not yet supported |
| Governance | Optional Identity/RBAC, Policy approvals, one-time Permits, budgets, quotas, audit, usage, and Langfuse metadata export | Identity is not enabled by default; do not expose credential entry over anonymous public HTTP |
| Company | Company/Position/Appointment, goals, Operations, Business Objects, reviewed PostgreSQL memory, internal finance controls, and installable Packs | External memory ranking, accounting, payments, and most live connectors are not part of the default product |
| Company | Company/Position/Appointment, goals, Operations, Business Objects, reviewed PostgreSQL memory with optional subject-scoped review hints, internal finance controls, and installable Packs | No automatic semantic contradiction verdict; external memory ranking, accounting, payments, and most live connectors are not part of the default product |
| Console | Guided task/team creation, model and employee setup, English/Chinese UI, work cards, pinned coordinated context transfers, and durable Mission Map replay | Transfer records start with new Runs; a dependency line alone is not evidence of an Agent message. The game-style Office is retired |
| Runtime and operations | PostgreSQL business ledger, Redis Streams delivery, LangGraph checkpointing, Compose, CI, backup/restore runbooks; production-mode startup rejects disabled RBAC and bundled database credentials | The startup guard is only a baseline check, not production qualification; framework-neutral cutover, durability/chaos/HA, HTTPS ingress, and restore evidence remain open |

Expand All @@ -37,6 +37,8 @@ See the [machine-readable report](qualification/a4-2-parity.json) and

## What remains

- Configurable deterministic acceptance for Coordinated business deliverables, distinct from
execution completion ([#187](https://github.com/0YHR0/AgentMesh/issues/187)).
- Durable non-LangGraph reattach/restart and production admission ([#136](https://github.com/0YHR0/AgentMesh/issues/136)).
- Shared Governed Action SDK beyond MCP/A2A ([#137](https://github.com/0YHR0/AgentMesh/issues/137)).
- Repeatable chaos and correctness qualification ([#138](https://github.com/0YHR0/AgentMesh/issues/138)).
Expand Down
33 changes: 33 additions & 0 deletions docs/model-and-memory-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,39 @@ Automatic learning from task results is a separate explicit option, off by defau
still produces candidates for review rather than automatically turning every sentence into trusted
knowledge. Reviewing a note does not by itself establish factual accuracy.

## Memory subjects and review hints

When adding a company note, **Subject key** is optional. Use a stable key for one fact or decision,
for example `release.label-color` and `release.rollout-thresholds`. A key is normalized to lowercase
and accepts 1–128 ASCII letters/digits and `. _ : / -`. Do not include secrets in it. API note and
candidate creation accept `subject_key` too. Existing notes are not automatically relabeled.

Retrieval returns `conflict_status`, `conflict_reason`, and `competing_memory_ids`:

- `UNKNOWN`: no explicit subject, so compatibility has not been assessed. It does **not** mean
contradictory records were detected or an accepted policy is inapplicable or withdrawn.
- `NO_COMPETING_RECORDS`: no other authorized active content has the same subject within this
company, namespace and Memory Type. This is not a guarantee of semantic consistency.
- `REVIEW_REQUIRED`: different active contents share that scoped subject. They might be compatible;
review the evidence, reject an incorrect candidate, revoke an obsolete note, or propose a replacement
with `supersedes_id` and approve it. The system does not guess a winner or overwrite a note.

For example, a blue-label rule and a margin threshold are not competing merely because both are
DECISION records. Even two rules with the same subject are not automatically confirmed contradictions.
Assessment considers all authorized active retrieval candidates before the count/token limit, so
showing only one result does not hide a competing record. Superseded, revoked, expired and unreviewed
notes do not count. An approved replacement inherits its predecessor's subject when omitted and
cannot change an existing subject; the old version is retired atomically.

Competing IDs are a deterministic sample capped at 10 per record. `competing_memory_count` is the
full authorized count; `competing_ids_truncated` indicates an incomplete sample, not fewer actual
competitors. The retrieval budget estimates serialized record content **and metadata** (four
characters per token, rounded up); it is not a provider-tokenizer guarantee or a whole-prompt budget.

Client compatibility: legacy `conflict` is now `null` for UNKNOWN/REVIEW_REQUIRED and `false` for
NO_COMPETING_RECORDS. Prefer the explicit status. New Run contexts carry the assessment and explain
its limits to the employee; historical snapshots are left unchanged.

## Final deliverables and incomplete replies

For coordinated work, **Primary deliverable** defaults to Automatic: a single final work item
Expand Down
29 changes: 29 additions & 0 deletions docs/model-and-memory-setup.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,35 @@ MemOS Key,并开启远端数据传输开关。默认全部关闭。不要把 K
自动从任务结果提取知识是另一个显式选项,默认关闭。即使开启,提取结果仍需审核;它不会
把每句话都自动变成员工长期记忆。审核可以减少错误知识积累,但不能代替对事实的验证。

## 记忆主题与核实提示

添加公司记忆时,可以填写可选的“主题键”,例如 `release.label-color`(发布标签颜色)和
`release.rollout-thresholds`(推广门槛)。同一事实或决策的版本使用相同主题键。
键会转为小写,允许 1–128 个 ASCII 字母、数字以及 `. _ : / -`,不要包含密钥。
API 的笔记和候选记忆创建也支持 `subject_key`。旧笔记不会被自动猜测主题或改写。

检索结果提供 `conflict_status`、`conflict_reason` 和 `competing_memory_ids`:

- `UNKNOWN`:未填写主题键,尚未判定兼容性,不代表已经发现矛盾,也不代表已批准的规则失效。
- `NO_COMPETING_RECORDS`:同一公司、命名空间、记忆类型和主题下,没有其他不同的有效内容。
这不是语义正确或绝对一致的保证。
- `REVIEW_REQUIRED`:同主题有不同的有效内容,需要核实,但它们可能互相兼容。
请审核证据、拒绝错误候选、撤销过时记忆,或通过 `supersedes_id` 提交并批准替代版本。
系统不会自行选择胜者或覆盖旧记忆。

例如“标签用蓝色”和“推广必须达到毛利门槛”即使同为 DECISION,也不会仅凭内容不同就被判为冲突。
检查基于检索范围内全部已授权的有效候选,在数量和 Token 截断前完成;只展示一条结果也不会
隐藏同主题的其他版本。未审核、已替代、已撤销和已过期记忆不参与检查。
替代版本未填写主题键时继承旧版本;已有主题不能跨主题替换。批准后旧版本同时退役。

每条记忆最多携带 10 个稳定排序的相关 ID;`competing_memory_count` 是完整的已授权数量,
`competing_ids_truncated` 表示 ID 样本被截短,不表示实际记录更少。检索预算同时估算序列化的
记忆内容和元数据,按每 4 个字符一个 Token 向上取整;这不是供应商精确分词或整个提示词的预算保证。

兼容性:旧字段 `conflict` 在 UNKNOWN/REVIEW_REQUIRED 时为 `null`,在
NO_COMPETING_RECORDS 时为 `false`;客户端应改用明确状态。新 Run 会提供核实信息并向员工
说明边界,历史任务快照不会重写。

## 最终交付物与不完整回复

协作任务的“主要交付物”默认使用自动规则:只有一个终点工作项时,它成为主要结果;有多个
Expand Down
2 changes: 1 addition & 1 deletion docs/qualification/a4-2-coordinated-activation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schema": "agentmesh.qualification.a4-2-coordinated-activation.v1",
"milestone": "A4.2c.2f8",
"status": "pending_activation",
"migration_head": "20260929_0056",
"migration_head": "20260930_0057",
"downgrade_floor": "20260915_0053",
"previous_migration_head": "20260915_0053",
"feature_gate": {
Expand Down
4 changes: 4 additions & 0 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ only; it is not a claim that a proposal has shipped.

## Next product validation

- Next priority: opt-in acceptance checks for Coordinated deliverables
([#187](https://github.com/0YHR0/AgentMesh/issues/187)). Reuse the existing Reviewed/checking
primitives where possible; make missing inputs, denominator/unit mismatches and human review
visible without complicating simple tasks. Complete provider output is not business acceptance.
- Make one real-model customer-feedback workflow easy to repeat from the Console; use the
[screenshot walkthrough](scenarios/customer-feedback-deepseek.md) as the current acceptance
example. A private DeepSeek run passed; the public demo remains keyless.
Expand Down
6 changes: 4 additions & 2 deletions src/agentmesh/api/console_assets/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ function renderMemoryList() {
const query = $("search").value.trim().toLowerCase();
const values = state.memoryRecords.filter((item) => {
const memory = item.memory;
return `${memory.content} ${memory.memory_type} ${memory.namespace_type} ${memory.namespace_id} ${memory.status}`.toLowerCase().includes(query);
return `${memory.content} ${memory.subject_key || ""} ${memory.memory_type} ${memory.namespace_type} ${memory.namespace_id} ${memory.status}`.toLowerCase().includes(query);
});
$("task-list").innerHTML = state.memoryError
? `<div class="empty-dag audit-error">${escapeHtml(state.memoryError)}</div>`
Expand Down Expand Up @@ -555,6 +555,7 @@ function memoryCard(snapshot, { review = false } = {}) {
return `<article class="memory-card ${statusClass(memory.status)}" data-memory-card-id="${memory.id}">
<div class="memory-card-head"><div><span class="pill">${escapeHtml(memory.memory_type)}</span><span class="pill">${escapeHtml(memory.namespace_type)}</span></div><span class="status-dot ${statusClass(memory.status)}">${escapeHtml(memory.status)}</span></div>
<p>${escapeHtml(memory.content)}</p>
<small>${t("Subject")}: ${escapeHtml(memory.subject_key || t("Unspecified · conflict not assessed"))}</small>
<div class="memory-evidence">${evidence || `<span>${t("没有证据摘要")}</span>`}</div>
<footer><code>${escapeHtml(shortId(memory.id))} · ${escapeHtml(memory.provenance_type)}</code><span>${memory.confidence_basis_points / 100}% · ${age(memory.created_at)}</span></footer>
${actions}
Expand Down Expand Up @@ -632,9 +633,10 @@ async function saveManualMemoryNote(event) {
try {
const snapshot = await api(`/api/v1/companies/${encodeURIComponent(companyId)}/memory/notes`, {
method: "POST",
body: JSON.stringify({ policy_id: policyId, content: $("manual-memory-content").value.trim(), memory_type: $("manual-memory-type").value })
body: JSON.stringify({ policy_id: policyId, content: $("manual-memory-content").value.trim(), memory_type: $("manual-memory-type").value, subject_key: $("manual-memory-subject").value.trim() || null })
});
$("manual-memory-content").value = "";
$("manual-memory-subject").value = "";
state.selectedMemoryId = snapshot.memory.id;
await loadMemory({ quiet: true });
toast(t("Company note saved; check its policy status in the inbox or ledger."));
Expand Down
5 changes: 5 additions & 0 deletions src/agentmesh/api/console_assets/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,11 @@
"Configure an active company and reviewed memory policy first.": "请先配置活跃公司和记忆审核策略。",
"MANUAL CAPTURE": "手动记录",
"Add a company note": "添加公司记忆",
"Subject key (optional)": "主题键(可选)",
"Subject": "主题",
"e.g. release.label-color": "例如 release.label-color",
"Unspecified · conflict not assessed": "未指定 · 未判定冲突",
"Use the same key for versions of one fact or decision. Different contents require review, not an automatic conflict verdict. Leave blank if unsure.": "同一事实或决策的不同版本使用相同主题键。内容不同只提示需要核实,不会自动认定冲突。不确定时可留空。",
"Creates a company-scoped note with server-derived provenance and evidence. Its status follows the active policy; review candidates in the inbox below.": "创建带有服务端来源和证据的公司级记忆。其状态遵循当前策略;可在下方收件箱审核候选记忆。",
"Memory type": "记忆类型",
"Active policy": "当前策略",
Expand Down
5 changes: 4 additions & 1 deletion src/agentmesh/api/console_assets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,10 @@ <h2>组织记忆控制台</h2>
<article><span>任务召回</span><strong id="memory-retrieval-count">0</strong><small>可审计检索记录</small></article>
<article><span>活动策略</span><strong id="memory-policy-count">0</strong><small>命名空间与审核边界</small></article>
</div>
<section class="panel manual-memory-panel"><div class="panel-title"><div><span class="eyebrow">MANUAL CAPTURE</span><h3>Add a company note</h3></div></div><p class="muted">Creates a company-scoped note with server-derived provenance and evidence. Its status follows the active policy; review candidates in the inbox below.</p><form id="manual-memory-form"><div class="form-row"><label>Memory type<select id="manual-memory-type"><option value="FACT">Fact</option><option value="PREFERENCE">Preference</option><option value="DECISION">Decision</option><option value="PATTERN">Pattern</option><option value="PROCEDURE">Procedure</option><option value="FEEDBACK">Feedback</option><option value="RELATIONSHIP">Relationship</option></select></label><label>Active policy<select id="manual-memory-policy" required></select></label></div><label>Note<textarea id="manual-memory-content" required maxlength="8000" placeholder="Capture a concise, durable company fact or decision."></textarea></label><p id="manual-memory-error" class="form-error" role="alert"></p><button id="manual-memory-submit" class="button primary" type="submit" disabled>Save company note</button></form></section>
<section class="panel manual-memory-panel"><div class="panel-title"><div><span class="eyebrow">MANUAL CAPTURE</span><h3>Add a company note</h3></div></div><p class="muted">Creates a company-scoped note with server-derived provenance and evidence. Its status follows the active policy; review candidates in the inbox below.</p><form id="manual-memory-form"><div class="form-row"><label>Memory type<select id="manual-memory-type"><option value="FACT">Fact</option><option value="PREFERENCE">Preference</option><option value="DECISION">Decision</option><option value="PATTERN">Pattern</option><option value="PROCEDURE">Procedure</option><option value="FEEDBACK">Feedback</option><option value="RELATIONSHIP">Relationship</option></select></label><label>Active policy<select id="manual-memory-policy" required></select></label></div>
<label>Subject key (optional)<input id="manual-memory-subject" maxlength="128" placeholder="e.g. release.label-color"></label>
<p class="muted">Use the same key for versions of one fact or decision. Different contents require review, not an automatic conflict verdict. Leave blank if unsure.</p>
<label>Note<textarea id="manual-memory-content" required maxlength="8000" placeholder="Capture a concise, durable company fact or decision."></textarea></label><p id="manual-memory-error" class="form-error" role="alert"></p><button id="manual-memory-submit" class="button primary" type="submit" disabled>Save company note</button></form></section>
<section id="external-memory-panel" class="panel hidden"><div class="panel-title"><div><span class="eyebrow">OPTIONAL REMOTE MEMORY</span><h3>MemOS Cloud pilot</h3></div><span class="pill">OPT-IN</span></div><p class="muted">Only approved public/internal notes under the active policy are sent to MemOS. This replaces the dedicated remote mirror; local PostgreSQL remains authoritative. Sync again after review or revocation.</p><button id="sync-external-memory" class="button subtle" type="button">Sync approved notes to MemOS</button><p id="external-memory-status" class="muted" role="status"></p></section>
<div id="memory-error" class="empty-dag audit-error hidden"></div>
<section id="memory-policy-strip" class="memory-policy-strip"></section>
Expand Down
1 change: 1 addition & 0 deletions src/agentmesh/api/organizational_memory_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ def create_manual_note(
company_id,
policy_id=payload.policy_id,
content=payload.content,
subject_key=payload.subject_key,
memory_type=payload.memory_type,
actor=principal.principal_id,
)
Expand Down
Loading
Loading