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
32 changes: 21 additions & 11 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,16 @@ Console 的 `/personal/agent` 是同一工作流的可选单页演示,沿用
ULTICODE_APP_BASE=http://127.0.0.1:9103 \
ULTICODE_AUTH_BASE=http://127.0.0.1:9101 \
ULTICODE_AGENT_ORIGIN=http://localhost:9002 \
uv run uvicorn --factory agent_service.app:create_app --app-dir src --host 127.0.0.1 --port 8000
uv run uvicorn --factory agent_service.runtime:create_app --app-dir src --host 127.0.0.1 --port 8000
```

真实 UltiCode HTTP / 模型 e2e 均为显式 opt-in。`e2e_sourced_analysis.py` uses agent-authored synthetic Markdown—not submissions, DTOs, or licensed user material—and validates a read-only submission projection without a real model. U03 workflow model analysis additionally requires a valid U02 gate and active budget authorization; other evaluation scripts follow their own gates. Supply credentials through a secure environment/secret store, never command text or logs. Runner contracts live in source and Linear; keep per-run results out of core docs.
默认启动只提供线程与会话 API,实时分析保持关闭。正式验收实时分析仍须设置 `ULTICODE_AGENT_LIVE_ANALYSIS=1`、`ULTICODE_AGENT_U02_GATE_PATH`、`ULTICODE_AGENT_EXPECTED_HEAD` 和 `ULTICODE_AGENT_EXPECTED_BASE`;gate 必须绑定当前候选。Agent 从已验证 gate 的预算锚点读取周期身份,核对现有活动账本及共享 guard,并使用授权的 `u03_analysis` / `u03_citation_judge` lanes。

本地手动真实模型冒烟测试不再等待 U02 验收 gate,但只能使用专用、一次性、封顶的分析预算。首次在 `services/agent/` 执行 `uv run python prepare_manual_live_test_budget.py`,它会创建并激活固定 `$182.00` 的账本以及空的私有共享 guard;该金额是 `$200` 累计授权扣除既有 `$15.024914` committed 与 `$2.359296` unresolved exposure 后的保守新额度,未知费用不会释放。若准备过程曾在账本激活后中断,脚本只会复用身份匹配、仍活动且调用/预留/实际费用/未知用量全为零的周期来补建缺失 guard;已有 guard 不会被覆盖,其他已有槽位也不会重建。随后仅在安全环境显式设置 `ULTICODE_AGENT_LIVE_ANALYSIS=1` 和 `ULTICODE_AGENT_MANUAL_ANALYSIS_ONLY=1`,并提供 `DEEPSEEK_MODEL=deepseek-flash` 与 `DEEPSEEK_API_KEY`。运行时只读取并锁定既有活动账本/guard,不创建或重置它们,也不在启动时调用模型;共享 guard 同时只允许一个 Agent 进程持有。

手动模式只开放 `analyze`:当前登录会话、线程 owner 和本人提交归属检查保持启用。它只读取当前线程绑定的本人源码,通过无参数、请求期工具交给模型,并将源码视为不可信数据;源码上限为 12,000 字符,超限时在模型调用前失败。该模式不启用提交列表源码投影,也不改变正式 U02 的合成语料和 gate。引用在内存中核验,存储时仅保留声明、行范围和核验占位说明,不保留源码引用原文;源码正文不会进入工作流状态、事件或 checkpoint。没有有效 U02 gate 时,confirm/save/recovery 路由不会挂载。该模式证明一次本地真实模型交互,不构成 DAV-58、U02、DAV-46/U03 或 U04 正式验收。正式验收及其他 evaluation runner 继续使用各自的候选绑定 gate。`e2e_sourced_analysis.py` 使用 Agent 编写的合成 Markdown,不会调用真实模型。Runner 合约留在源码与 Linear,每次运行结果不写入核心文档。

对已有线程重试时,成功分析会清空 `receipt.failureReason`;之前失败的事件仍保留在该线程的事件历史中。

`DeepseekModel` requests provider JSON Output with `response_format={"type":"json_object"}` and an explicit JSON prompt. The guard accepts only that exact format when supplied; legacy requests may omit the field. Empty, truncated, malformed or schema-invalid decisions still fail strict validation after known usage is settled. JSON Output does not replace authorization, tool argument validation or citation verification. See [DeepSeek JSON Output](https://api-docs.deepseek.com/guides/json_mode/).

Expand Down Expand Up @@ -318,11 +324,13 @@ its existing signature and delegates to that graph, preserving four-round and 30
trace results, bounded tool errors, and cancellation propagation. The checkpointed workflow graph
dispatches only server-validated actions and uses the same read-only LangGraph kernel for analysis.
An injected `offline_model_factory` can run a scripted model through that workflow for offline
verification. Live analysis uses the same kernel only when a current evidence-bound U02 gate is
valid and the request is configured with the expected budget period, shared guard, and legal
`u03_analysis` purpose. `authorized_model(...)` and the guarded transport enforce the existing
budget policy; citation judging requires the separate `u03_citation_judge` purpose. Missing or
invalid gate/budget authorization fails closed with `503 model_budget_blocked` before model calls.
verification. Formal live analysis uses the same kernel only when a current evidence-bound U02 gate
is valid and the request is configured with the expected budget period, shared guard, and legal
`u03_analysis` purpose. A separately opted-in local manual mode can run read-only analysis with its
fixed one-shot budget and shared guard; it does not mount confirm/save/recovery routes or count as
formal acceptance. `authorized_model(...)` and the guarded transport enforce the bound budget;
citation judging requires the separate `u03_citation_judge` purpose. Missing or invalid mode/budget
authorization fails closed with `503 model_budget_blocked` before model calls.
The provider adapter unwraps the provider response envelope; the workflow parser accepts only the
strict inner `{"text": "...", "citations": [...]}` JSON object, not a second provider envelope.
This preserves the existing model/client contract and rejects extra or malformed inner fields.
Expand Down Expand Up @@ -358,10 +366,12 @@ keys, non-finite numbers, extra fields, and oversized bodies are rejected before
The Agent does not issue or refresh login cookies, accept caller-supplied identity, expose CORS,
or persist credentials.

The workflow factory loads an evidence-bound U02 gate against the expected candidate head/base.
Confirm, save, and recovery routes are registered only when that gate validates. Live model calls
also require the expected budget period, shared guard, and policy-authorized analysis/judge
purposes; missing authorization fails closed rather than making a provider request. The workflow
The formal acceptance workflow loads an evidence-bound U02 gate against the expected candidate
head/base. Confirm, save, and recovery routes are registered only when that gate validates. Live
model calls also require the expected budget period, shared guard, and policy-authorized
analysis/judge purposes; missing authorization fails closed rather than making a provider request.
The separate local manual smoke mode bypasses only this acceptance gate for read-only analysis and
never creates an acceptance artifact. The workflow
validates answer text against existing bounded source-fact, negation-aware boundary, source-reference,
and tool-trace checks; these guards are not a claim of perfect semantic verification. Nonempty
citations must match same-run retrieved evidence, pass document integrity, and receive judge support
Expand Down
32 changes: 21 additions & 11 deletions docs/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ cannot select a user, model, graph node, or checkpoint.

| Operation | Request body | Purpose |
| --- | --- | --- |
| `POST /agent/threads` | `{"sourceSubmissionId": "...", "question": "..."}` | Verify caller-owned source, create thread and offline draft |
| `POST /agent/threads` | `{"sourceSubmissionId": "<canonical UUID>", "question": "..."}` | Verify caller-owned source, create thread and offline draft |
| `GET /agent/threads/{thread_id}` | — | Read caller's canonical workflow and draft |
| `GET /agent/threads/{thread_id}/events?after=N` | — | Read bounded event page; does not resume workflow |
| `POST /agent/threads/{thread_id}/analyze` | `{}` | Explicit analysis request through the shared graph; requires injected offline model factory or live model authorization |
Expand All @@ -51,10 +51,15 @@ GET thread responses expose `threadId`, `runId`, `status`, `sourceSubmissionId`,
versioned `draft` (`title`, `content`, `facts`, `hypotheses`, `citations`, `citationChecks`,
`sampleScope`), `paramsDigest`, `analysis`, a redacted `confirmation` summary, and `receipt`
(`planId`, `cancelRequested`, `failureReason`). They do not expose owner IDs or the business key.
Draft facts are derived from the validated metadata projection; source code and test data are not
included. `sampleScope` marks the checked-in synthetic corpus. Initial offline-draft citations only
establish source traceability; model-answer citations, when present, are added only after same-run
retrieval, document-integrity, support, and derivability checks.
Draft facts are derived from the validated metadata projection; the general submission-list tools
never expose source code or test data. In explicit local manual smoke mode only, analysis may read
the exact owner-verified submission already bound to the thread through a no-argument,
request-scoped tool. Source is untrusted input and capped at 12,000 characters; missing or oversized
source fails before provider dispatch. The source body is not stored in workflow rows, events, or
checkpoints. Source citations are checked in memory and persisted without their quoted source text.
`sampleScope` identifies whether an analysis used the checked-in synthetic corpus or the
owner-authorized thread source. Model-answer citations are added only after same-run retrieval,
document-integrity, support, and derivability checks.
The Agent keeps the business idempotency key private. Its recovery action uses that original key
for owner-scoped by-key reconciliation; a user-facing saved-record readback uses
`GET /learning-plans/{planId}` with the returned `planId`.
Expand Down Expand Up @@ -103,13 +108,17 @@ Request bodies reject identity fields. The service does not refresh sessions, se
configure cross-origin access.

The evidence-bound `ulticode-u02-gate-v1` loader checks candidate head/base and referenced DAV-58,
DAV-53, budget-audit, and prior-five evidence against their SHA-256 digests. Confirm, save, and
recovery routes are registered only when that gate validates. Live model requests additionally
require the expected budget period, shared budget guard, and policy-authorized purpose:
DAV-53, budget-audit, and prior-five evidence against their SHA-256 digests. Formal confirm, save,
and recovery routes are registered only when that gate validates. Formal live model requests
additionally require the expected budget period, shared budget guard, and policy-authorized purpose:
`u03_analysis` for the analysis model and `u03_citation_judge` for citation judgments. The
authorized model and guarded transport use the existing period/lane limits; missing or invalid
authorization fails closed with `503 model_budget_blocked` before a provider request. This is not
evidence that a real acceptance run has passed.
authorization fails closed with `503 model_budget_blocked` before a provider request. An explicit
local manual smoke mode permits only read-only analysis under its fixed one-shot budget and shared
guard; it may read only the owner-verified source already bound to the thread, using a no-argument
request-scoped tool. The source is capped at 12,000 characters, treated as untrusted input, and not
stored; citation excerpts are redacted after in-memory verification. It mounts no confirm/save/recovery
routes and is not evidence that U02/U03/U04 acceptance has passed.

The workflow runs analysis through the shared checkpointed action graph and read-only model/tool
kernel. Answer text must pass bounded source-fact, negation-aware boundary, source-reference, and
Expand All @@ -121,7 +130,8 @@ only when the answer itself satisfies the boundary checks. Offline scripted-mode
tests are not live acceptance evidence.

Without a valid U02 gate, confirm/save/recover routes are not mounted; requests to those paths use
the normal not-found response envelope. A valid gate alone does not authorize model calls.
the normal not-found response envelope, including in local manual smoke mode. A valid gate alone
does not authorize model calls.

For the opt-in U02/U03/U04 candidate-freeze, gate, and acceptance-bundle commands, see the
[immutable acceptance workflow](DEVELOPMENT.md#u02-u03-u04-immutable-acceptance-chain).
Expand Down
37 changes: 34 additions & 3 deletions services/agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,47 @@ Workflow route and field contracts, U02 evidence gate, and budget behavior are i
[Development guide](../../docs/DEVELOPMENT.md#u03-agent-workflow).

Offline scripted-model analysis can be injected into the checkpointed workflow and uses the same
bounded read-only LangGraph kernel. Live analysis is fail-closed unless the evidence-bound U02 gate,
expected budget period, shared budget guard, and authorized `u03_analysis` purpose are valid;
citation judging uses the separate `u03_citation_judge` purpose. Missing authorization returns
bounded read-only LangGraph kernel. Formal live analysis is fail-closed unless the evidence-bound
U02 gate, expected budget period, shared budget guard, and authorized `u03_analysis` purpose are
valid; citation judging uses the separate `u03_citation_judge` purpose. A local manual smoke mode
can bypass only the formal acceptance gate for read-only analysis using its fixed one-shot budget;
it does not mount confirmation, save, or recovery routes. Missing authorization returns
`503 model_budget_blocked` before provider calls. Nonempty citations must match same-run retrieved
evidence, pass integrity checks, and be judged as supporting and derivable; unknown judge usage
rejects analysis. Empty citations are accepted only after the bounded source-fact/tool-trace/source-
reference answer checks. These are fail-closed safeguards, not perfect semantic verification.
Offline scripted models and `httpx.MockTransport` do not establish real-model acceptance, live Java
persistence, or complete U03 acceptance.

In this manual mode only, analysis reads the exact submission already bound to the owner-verified
thread through a no-argument, request-scoped tool. Source is treated as untrusted input and capped at
12,000 characters; missing or oversized source stops before a provider call. The generic submission
listing tools remain metadata-only. Full source and citation excerpts are not written to the Agent
store, events, or checkpoints; citation excerpts are integrity-checked in memory and replaced with a
redaction note before storage. This local smoke path is not a substitute for formal U02/U03/U04
acceptance. Analysis errors keep the generic `upstream_unavailable` response. Service logs record
only the failure stage and a safe reason code; prompts, submission source, and model answers are
never logged. Manual sourced answers may format complexity notation inline, while uncited exact
source lines and source identifiers remain rejected. A successful retry clears the prior
`receipt.failureReason`; the earlier failure remains in the thread's event history.

For the local HTTP demo, start Uvicorn with `agent_service.runtime:create_app`. Live analysis is
off by default. Formal acceptance mode requires `ULTICODE_AGENT_LIVE_ANALYSIS=1`, a current private
U02 gate, and its exact `ULTICODE_AGENT_EXPECTED_HEAD` and `ULTICODE_AGENT_EXPECTED_BASE` bindings.
For a local real-model smoke test, run `uv run python prepare_manual_live_test_budget.py` from
this directory, then set `ULTICODE_AGENT_LIVE_ANALYSIS=1` and
`ULTICODE_AGENT_MANUAL_ANALYSIS_ONLY=1`. This creates the fixed `$182.00` budget and its empty,
private shared guard to keep the existing `$15.024914` committed plus `$2.359296` unresolved
exposure under the approved `$200` cumulative ceiling; unknown usage remains reserved. If setup
stopped after activating an unused budget, the script may finish only that exact active period
when its attempts, reservations, actual usage, and unknown usage are all zero. It never replaces an
existing guard or resets a period. The mode preserves session, owner, and source-ownership checks
but mounts only analysis. It is not formal U02/U03 acceptance. Both modes derive the period from
existing bound state and lock its shared guard; runtime startup does not create/reset accounting or
call the provider. Set `DEEPSEEK_MODEL=deepseek-flash` and keep the API key in a secure environment.
Keep one Agent server process per shared guard. Without a valid mode and budget, ordinary thread
operations remain available and analysis returns `503 model_budget_blocked`.

Runtime notes:
- `src/deepseek_model.py` is an external model adapter. Its API key is read from the environment and
is never logged or committed.
Expand Down
12 changes: 6 additions & 6 deletions services/agent/data/repository_corpus_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
},
{
"doc_id": "repository-development",
"version": "sha256-8517c5e06fed9982b083a67e58b7d08e4d536586a6de2f5572f0ffbfaf9bbaaa",
"chunk_id": "repository-development:sha256-8517c5e06fed9982b083a67e58b7d08e4d536586a6de2f5572f0ffbfaf9bbaaa:1",
"version": "sha256-d0b07b9b30b1e4eb0bb9540bf26e3fc39b51f2ea3b95c5c9cb3814045a7c6751",
"chunk_id": "repository-development:sha256-d0b07b9b30b1e4eb0bb9540bf26e3fc39b51f2ea3b95c5c9cb3814045a7c6751:1",
"source_path": "docs/DEVELOPMENT.md",
"access_scope": "repository-public",
"sample_kind": "real",
Expand All @@ -57,16 +57,16 @@
},
{
"doc_id": "repository-reference",
"version": "sha256-c83b0fb388f997a93164377f16ab6aadb8cf0f6e7b1219f96561473ecfa613f8",
"chunk_id": "repository-reference:sha256-c83b0fb388f997a93164377f16ab6aadb8cf0f6e7b1219f96561473ecfa613f8:1",
"version": "sha256-107969feca9601dfa18e0d222ebce6feff7d2fcd3a8c2dbe23516ea5f40e5ed1",
"chunk_id": "repository-reference:sha256-107969feca9601dfa18e0d222ebce6feff7d2fcd3a8c2dbe23516ea5f40e5ed1:1",
"source_path": "docs/REFERENCE.md",
"access_scope": "repository-public",
"sample_kind": "real",
"permission": "MIT:LICENSE:sha256:2be36e9d56578c1111740b6fe339ea3619cf1f2000af718f1a59e97d2e5d995c",
"scope": "Repository documentation; local retrieval and evaluation under the included MIT license",
"source_position": "lines 162-178",
"source_position": "lines 176-182",
"model_input_projection": "SourceHit.as_model_dict()",
"source_trust": "untrusted-data",
"content_digest": "sha256:2bfd12ab6b6dc61d6e9fc80afd8337e6639509336df35a3d77bbd37757e6f036"
"content_digest": "sha256:2142c2f17b6ecf07cd8ca3e9c8202ac9ecda58fe658396ef19afbabfd78769fb"
}
]
Loading
Loading