Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
681b195776 | ||
|
|
59e796ba3f | ||
|
|
e6fdf94def | ||
|
|
4183ea77d9 | ||
|
|
9ec1bf7a9d | ||
|
|
2df0d10d96 | ||
|
|
8f113e2376 | ||
|
|
277392acf3 | ||
|
|
e05587f165 | ||
|
|
ad2649b4ab |
@@ -24,7 +24,7 @@ jobs:
|
||||
echo "SUBMODULE_TOKEN is not configured" >&2
|
||||
exit 1
|
||||
fi
|
||||
git config --global url."https://weichen:${SUBMODULE_TOKEN}@git-home.u1680832.nyat.app:30319/".insteadOf "ssh://git@git-ssh.u1680832.nyat.app:31411/"
|
||||
git config --global url."https://weichen:${SUBMODULE_TOKEN}@gitea.naitangbaobao.cn/".insteadOf "ssh://git@gitea.naitangbaobao.cn:52222/"
|
||||
git -c fetch.recurseSubmodules=false submodule update --init --recursive
|
||||
- name: Install Go 1.27.1
|
||||
run: |
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
parsed_server = urlsplit(SERVER)
|
||||
if parsed_server.scheme not in {"http", "https"} or not parsed_server.netloc:
|
||||
sys.exit("Checkout server must be the platform-injected http(s) URL")
|
||||
SSH = "ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/"
|
||||
SSH = "ssh://git@gitea.naitangbaobao.cn:52222/weichen/"
|
||||
# 审查过的白名单,独立于候选 .gitmodules:仅列出两个治理 gitlink。
|
||||
REPOSITORIES = {
|
||||
"deps/development-guidelines": "Development-Guidelines",
|
||||
|
||||
+5
-5
@@ -1,15 +1,15 @@
|
||||
[submodule "deps/development-guidelines"]
|
||||
path = deps/development-guidelines
|
||||
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Guidelines.git
|
||||
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Development-Guidelines.git
|
||||
[submodule "deps/error-code-system"]
|
||||
path = deps/error-code-system
|
||||
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Error-Code-System.git
|
||||
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Error-Code-System.git
|
||||
[submodule "deps/logging-system"]
|
||||
path = deps/logging-system
|
||||
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Logging-System.git
|
||||
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Logging-System.git
|
||||
[submodule "deps/agent-intent"]
|
||||
path = deps/agent-intent
|
||||
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Intent.git
|
||||
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Intent.git
|
||||
[submodule "deps/development-manager"]
|
||||
path = deps/development-manager
|
||||
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Manager.git
|
||||
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Development-Manager.git
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
历史文档与旧链接里的 `git-panel.u1680832.nyat.app:30319` 已失效(TLS 握手失败),
|
||||
见到一律按过期处理,不要再试。当前权威通道:
|
||||
|
||||
- **Web / API(HTTPS)**:`https://git-home.u1680832.nyat.app:30319`(Gitea 1.27.3,
|
||||
- **Web / API(HTTPS)**:`https://gitea.naitangbaobao.cn`(Gitea 1.27.3,
|
||||
API 前缀 `/api/v1`;偶发 broken pipe / 超时,重试即可)。
|
||||
- **Git over SSH**:`ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/<Repo>.git`
|
||||
- **Git over SSH**:`ssh://git@gitea.naitangbaobao.cn:52222/weichen/<Repo>.git`
|
||||
(各仓 origin 与 gitlink 均为此格式)。
|
||||
- **API token**:`~/.secrets/gitea`,两行键值 `URL_PREFIX=…` 与
|
||||
`ACCESS_TOKEN=<40 位 hex>`;取值 `grep ACCESS_TOKEN ~/.secrets/gitea | cut -d= -f2-`,
|
||||
@@ -33,7 +33,7 @@
|
||||
(baseline 硬边界 2:只记录来源、字段与可用状态)。
|
||||
- **SSH key**:`~/.ssh/home_gitea`(ED25519,公钥指纹
|
||||
`SHA256:GYXaOXIMeloQ1fKSfdJ/ndgPQzs/Ix7Hk62ekfkfQ20`,Gitea 侧密钥名 GMKtec);
|
||||
`~/.ssh/config` 已有 `git-ssh.u1680832.nyat.app` 主机条目,克隆/推送直接可用。
|
||||
`~/.ssh/config` 已有 `gitea.naitangbaobao.cn(端口 52222)` 主机条目,克隆/推送直接可用。
|
||||
|
||||
## Agent 执行与新项目准入(强制)
|
||||
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
|
||||
- 目标/产品边界:独立的 Agent 执行基础库。提供执行契约(contract)、执行端口(exec)、自研运行时(runtime)、外部适配器(adapters)与行为验收(conformance)。不实现小队编排,不依赖 Core 或 Squad。
|
||||
- 源码、资产、文档、机器契约位置:Go 源码在仓库根包目录;模块路径 `agent-native`;人类文档在根 `README.md`、`docs/`、`policy/`;过程记录在 `docs/records/`;机器契约以 `contract` 包类型为准。
|
||||
- 权威远端、集成基线、受保护分支:`ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git`,集成基线 `main`。
|
||||
- 权威远端、集成基线、受保护分支:`ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git`,集成基线 `main`。
|
||||
- 并行共同基线记录位置、合入通知/主动检查方式:任务主记录在 Gitea Issue/PR;合入前在本仓 `main` 上 `git fetch` 并确认 HEAD。
|
||||
- 发布线与批准版本/实际制品查询入口:当前无独立制品仓库。可构建性以本仓 `main` 的 `go test` 为准;依赖子模块版本以 gitlink 为准,不把工作区未提交文件当发布组合。
|
||||
- 提交/审核/合并/发布身份与权限:仓库所有者 weichen。本机提交不代替远端合并。
|
||||
@@ -28,7 +28,7 @@
|
||||
克隆:
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git
|
||||
git clone --recurse-submodules ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git
|
||||
# 已克隆时:git submodule update --init --recursive
|
||||
```
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
版本以本仓 gitlink 为准。`scripts/submodule-consistency.sh` 核对 gitlink 与检出的 HEAD。
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git
|
||||
git clone --recurse-submodules ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git
|
||||
# 已克隆时:git submodule update --init --recursive
|
||||
```
|
||||
|
||||
@@ -83,7 +83,7 @@ replace agent-native => ./deps/agent-native
|
||||
|
||||
本仓自己的 `go.mod` 则把错误码库和日志库替换到 `./deps/`。消费方若同时依赖这三仓,必须在消费方 `go.mod` 里写自己的 `replace`:依赖模块内部的 `replace` 不会在上层构建中生效。
|
||||
|
||||
远程:`ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git`
|
||||
远程:`ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git`
|
||||
|
||||
## CI
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"agent-native/exec"
|
||||
@@ -57,6 +58,14 @@ func captureText(ctx context.Context, text string) {
|
||||
|
||||
// scopeIdentity returns a stable non-empty identity string for a non-zero
|
||||
// SessionScope, or "" for the legacy one-shot / empty-scope path.
|
||||
//
|
||||
// Encoding (collision-free when components contain "/"):
|
||||
// - Legacy (no component contains "/"): tenant + "/" + project + "/" + session
|
||||
// so existing workspaces keep the same hashed transcript filenames.
|
||||
// - Otherwise: length-prefixed concatenation of each trimmed component as
|
||||
// strconv.Itoa(len(part)) + ":" + part (no extra separators). Distinct
|
||||
// scopes such as {tenant:"a/b", project:"c"} vs {tenant:"a", project:"b/c"}
|
||||
// therefore produce different identity strings and transcript paths.
|
||||
func scopeIdentity(s exec.SessionScope) string {
|
||||
t := strings.TrimSpace(s.Tenant)
|
||||
p := strings.TrimSpace(s.Project)
|
||||
@@ -64,6 +73,11 @@ func scopeIdentity(s exec.SessionScope) string {
|
||||
if t == "" && p == "" && sess == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.Contains(t, "/") || strings.Contains(p, "/") || strings.Contains(sess, "/") {
|
||||
return strconv.Itoa(len(t)) + ":" + t +
|
||||
strconv.Itoa(len(p)) + ":" + p +
|
||||
strconv.Itoa(len(sess)) + ":" + sess
|
||||
}
|
||||
return t + "/" + p + "/" + sess
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,92 @@ func TestContractOldStoreWithoutIdentityNotAdopted(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestScopeIdentitySlashCollisionFree: tenant/project values that collide under
|
||||
// naive "/" joins must yield distinct identities and transcript paths (M1).
|
||||
func TestScopeIdentitySlashCollisionFree(t *testing.T) {
|
||||
scopeAB := exec.SessionScope{Tenant: "a/b", Project: "c", Session: "s"}
|
||||
scopeAC := exec.SessionScope{Tenant: "a", Project: "b/c", Session: "s"}
|
||||
idAB := scopeIdentity(scopeAB)
|
||||
idAC := scopeIdentity(scopeAC)
|
||||
if idAB == "" || idAC == "" {
|
||||
t.Fatal("non-empty scopes must produce non-empty identities")
|
||||
}
|
||||
if idAB == idAC {
|
||||
t.Fatalf("slash-bearing scopes must not collide: both %q", idAB)
|
||||
}
|
||||
dir := t.TempDir()
|
||||
pathAB := transcriptPathForScope(dir, idAB)
|
||||
pathAC := transcriptPathForScope(dir, idAC)
|
||||
if pathAB == pathAC {
|
||||
t.Fatalf("distinct identities must hash to distinct transcript paths: %s", pathAB)
|
||||
}
|
||||
}
|
||||
|
||||
// TestScopeIdentityLegacySlashFreeUnchanged keeps product workspaces on the
|
||||
// historical identity string (and thus transcript filename) when no component
|
||||
// contains "/".
|
||||
func TestScopeIdentityLegacySlashFreeUnchanged(t *testing.T) {
|
||||
scope := exec.SessionScope{Tenant: "t1", Project: "p1", Session: "s-a"}
|
||||
const want = "t1/p1/s-a"
|
||||
if got := scopeIdentity(scope); got != want {
|
||||
t.Fatalf("slash-free identity: got %q want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestBindSessionScopeRejectsMismatchedSlashScope: exact-match check must
|
||||
// refuse when a store's recorded identity differs from the request, including
|
||||
// when both identities use the slash-safe encoding.
|
||||
func TestBindSessionScopeRejectsMismatchedSlashScope(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
scopeA := exec.SessionScope{Tenant: "a/b", Project: "c", Session: "sess"}
|
||||
scopeB := exec.SessionScope{Tenant: "a", Project: "b/c", Session: "sess"}
|
||||
idA := scopeIdentity(scopeA)
|
||||
idB := scopeIdentity(scopeB)
|
||||
if idA == idB {
|
||||
t.Fatal("precondition: slash scopes must differ")
|
||||
}
|
||||
path := transcriptPathForScope(dir, idA)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
store, err := session.Open(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := store.SaveMeta(map[string]string{"scope": idB}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b := New(Options{
|
||||
ModelOptions: ModelOptions{
|
||||
Model: "fake",
|
||||
Stream: script(llm.Message{Role: llm.RoleAssistant, Content: "x", StopReason: llm.StopEnd}),
|
||||
},
|
||||
})
|
||||
if err := b.bindSessionScope(store, idA, "fake", "e-mismatch"); err == nil {
|
||||
t.Fatal("expected scope identity mismatch")
|
||||
} else if !strings.Contains(err.Error(), "scope identity mismatch") {
|
||||
t.Fatalf("want mismatch error, got %v", err)
|
||||
}
|
||||
|
||||
// Contract path must also fail-close when meta disagrees with the request scope.
|
||||
res, err := b.Contract().Execute(context.Background(), exec.ContractRequest{
|
||||
ExecutionID: "e-mismatch",
|
||||
Prompt: "hi",
|
||||
SessionScope: scopeA,
|
||||
Workspace: exec.WorkspaceHandle{Root: dir},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("transport: %v", err)
|
||||
}
|
||||
if res.Outcome == exec.OutcomeSucceeded {
|
||||
t.Fatal("mismatched slash scope must not succeed")
|
||||
}
|
||||
if res.Err == nil || !strings.Contains(res.Err.Reason, "scope identity mismatch") {
|
||||
t.Fatalf("want mismatch refusal, got %+v", res.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContractWritableFileToolHonorsAllowlist(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
b := New(Options{
|
||||
|
||||
Vendored
+1
-1
Submodule deps/agent-intent updated: 7f3ff6a187...bff8c5ec68
Vendored
+1
-1
Submodule deps/development-guidelines updated: 2688fd2be6...3ed982138c
Vendored
+1
-1
Submodule deps/development-manager updated: bd3a7de57a...24e8a5c8ba
Vendored
+1
-1
Submodule deps/error-code-system updated: a3ee67bba2...00c03035b5
Vendored
+1
-1
Submodule deps/logging-system updated: 49b5d8be60...7005493077
Reference in New Issue
Block a user