@harrylabsj/kiwi 0.6.1 → 0.7.0
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 +28 -0
- package/contracts/candidate-agent-dto-1.0.README.md +12 -8
- package/contracts/conformance/python-service/README.md +19 -0
- package/contracts/conformance/python-service/run.py +134 -0
- package/contracts/kiwi-catalog/1.0/listing-record.schema.json +11 -1
- package/contracts/kiwi-contracts.lock.json +7 -0
- package/contracts/manifest.json +61 -0
- package/contracts/vectors/candidate-agent.invalid-private-field.json +7 -0
- package/contracts/vectors/candidate-agent.valid.json +26 -0
- package/dist/a2a/client/client.js +39 -34
- package/dist/a2a/client/client.js.map +1 -1
- package/dist/a2a/client/url-policy.d.ts +8 -1
- package/dist/a2a/client/url-policy.js +18 -2
- package/dist/a2a/client/url-policy.js.map +1 -1
- package/dist/a2a/clock.d.ts +30 -0
- package/dist/a2a/clock.js +39 -0
- package/dist/a2a/clock.js.map +1 -0
- package/dist/a2a/negotiate.d.ts +6 -0
- package/dist/a2a/negotiate.js +10 -12
- package/dist/a2a/negotiate.js.map +1 -1
- package/dist/a2a/node.d.ts +20 -2
- package/dist/a2a/node.js +165 -19
- package/dist/a2a/node.js.map +1 -1
- package/dist/a2a/server/auth.js +11 -2
- package/dist/a2a/server/auth.js.map +1 -1
- package/dist/a2a/server/merchant-handler.d.ts +4 -0
- package/dist/a2a/server/merchant-handler.js +283 -27
- package/dist/a2a/server/merchant-handler.js.map +1 -1
- package/dist/a2a/server/pipeline.d.ts +17 -0
- package/dist/a2a/server/pipeline.js +89 -1
- package/dist/a2a/server/pipeline.js.map +1 -1
- package/dist/a2a/server/ucp.d.ts +30 -2
- package/dist/a2a/server/ucp.js +23 -14
- package/dist/a2a/server/ucp.js.map +1 -1
- package/dist/agent/agent-db.js +5 -0
- package/dist/agent/agent-db.js.map +1 -1
- package/dist/agent/buyer/buyer-tools.d.ts +5 -0
- package/dist/agent/buyer/buyer-tools.js +75 -7
- package/dist/agent/buyer/buyer-tools.js.map +1 -1
- package/dist/agent/buyer/search-loop.d.ts +3 -0
- package/dist/agent/buyer/search-loop.js +129 -0
- package/dist/agent/buyer/search-loop.js.map +1 -1
- package/dist/agent/buyer/task-store.d.ts +2 -0
- package/dist/agent/buyer/task-store.js +11 -7
- package/dist/agent/buyer/task-store.js.map +1 -1
- package/dist/agent/kernel.d.ts +6 -0
- package/dist/agent/kernel.js +100 -10
- package/dist/agent/kernel.js.map +1 -1
- package/dist/agent/memory/schema.d.ts +1 -1
- package/dist/agent/memory/schema.js +7 -1
- package/dist/agent/memory/schema.js.map +1 -1
- package/dist/agent/memory/store.d.ts +5 -0
- package/dist/agent/memory/store.js +29 -1
- package/dist/agent/memory/store.js.map +1 -1
- package/dist/agent/merchant/action-candidate.js +15 -1
- package/dist/agent/merchant/action-candidate.js.map +1 -1
- package/dist/agent/merchant/merchant-client.js +22 -4
- package/dist/agent/merchant/merchant-client.js.map +1 -1
- package/dist/agent/merchant/types.d.ts +5 -2
- package/dist/agent/merchant/types.js +6 -2
- package/dist/agent/merchant/types.js.map +1 -1
- package/dist/agent/negotiation-chat.js +34 -14
- package/dist/agent/negotiation-chat.js.map +1 -1
- package/dist/cli.d.ts +56 -0
- package/dist/cli.js +51 -3
- package/dist/cli.js.map +1 -1
- package/dist/commerce/data-source.d.ts +3 -0
- package/dist/commerce/data-source.js.map +1 -1
- package/dist/commerce/http-client.js +35 -31
- package/dist/commerce/http-client.js.map +1 -1
- package/dist/commerce/shopping-cli-source.js +63 -46
- package/dist/commerce/shopping-cli-source.js.map +1 -1
- package/dist/counterparty/a2a-direct/index.d.ts +5 -0
- package/dist/counterparty/a2a-direct/index.js +24 -0
- package/dist/counterparty/a2a-direct/index.js.map +1 -1
- package/dist/counterparty/shopping-cli-hosted/index.js +52 -19
- package/dist/counterparty/shopping-cli-hosted/index.js.map +1 -1
- package/dist/discovery/catalog-source/kiwi-record.d.ts +2 -0
- package/dist/discovery/catalog-source/kiwi-record.js.map +1 -1
- package/dist/discovery/catalog-source/kiwi-source.js +39 -35
- package/dist/discovery/catalog-source/kiwi-source.js.map +1 -1
- package/dist/discovery/catalog-source/register.js +12 -1
- package/dist/discovery/catalog-source/register.js.map +1 -1
- package/dist/discovery/catalog-source/source.js +39 -35
- package/dist/discovery/catalog-source/source.js.map +1 -1
- package/dist/discovery/resolve.d.ts +15 -0
- package/dist/discovery/resolve.js +59 -35
- package/dist/discovery/resolve.js.map +1 -1
- package/dist/discovery/ucp/index.d.ts +1 -1
- package/dist/discovery/ucp/index.js +1 -1
- package/dist/discovery/ucp/index.js.map +1 -1
- package/dist/discovery/ucp/resolver.d.ts +5 -0
- package/dist/discovery/ucp/resolver.js +65 -38
- package/dist/discovery/ucp/resolver.js.map +1 -1
- package/dist/discovery/ucp/vendor.d.ts +1 -1
- package/dist/discovery/ucp/vendor.js +1 -1
- package/dist/handoff/delivery.d.ts +4 -2
- package/dist/handoff/delivery.js +6 -1
- package/dist/handoff/delivery.js.map +1 -1
- package/dist/handoff/index.d.ts +1 -1
- package/dist/handoff/index.js +1 -1
- package/dist/handoff/index.js.map +1 -1
- package/dist/handoff/ledger.d.ts +9 -0
- package/dist/handoff/ledger.js +66 -0
- package/dist/handoff/ledger.js.map +1 -1
- package/dist/handoff/transaction.d.ts +21 -3
- package/dist/handoff/transaction.js +37 -5
- package/dist/handoff/transaction.js.map +1 -1
- package/dist/handoff/ucp-checkout/channel.js +15 -10
- package/dist/handoff/ucp-checkout/channel.js.map +1 -1
- package/dist/negotiation/jcs.js +11 -8
- package/dist/negotiation/jcs.js.map +1 -1
- package/dist/negotiation/lease/store.d.ts +25 -0
- package/dist/negotiation/lease/store.js +101 -0
- package/dist/negotiation/lease/store.js.map +1 -0
- package/dist/negotiation/recovery/recover.js +25 -1
- package/dist/negotiation/recovery/recover.js.map +1 -1
- package/dist/operator/runner.d.ts +11 -0
- package/dist/operator/runner.js +20 -1
- package/dist/operator/runner.js.map +1 -1
- package/dist/product-catalog.d.ts +1 -1
- package/dist/product-catalog.js +3 -3
- package/dist/product-catalog.js.map +1 -1
- package/dist/product-cli.d.ts +1 -1
- package/dist/product-cli.js +1 -1
- package/dist/product-publish.d.ts +5 -0
- package/dist/product-publish.js +112 -7
- package/dist/product-publish.js.map +1 -1
- package/dist/supervisor/stack-config.d.ts +6 -1
- package/dist/supervisor/stack-config.js +11 -3
- package/dist/supervisor/stack-config.js.map +1 -1
- package/dist/trust/identity/message-signature.js +17 -0
- package/dist/trust/identity/message-signature.js.map +1 -1
- package/dist/weixin/channel.d.ts +2 -0
- package/dist/weixin/channel.js +17 -3
- package/dist/weixin/channel.js.map +1 -1
- package/dist/weixin/cli-weixin.js +2 -0
- package/dist/weixin/cli-weixin.js.map +1 -1
- package/dist/weixin/ilink-client.d.ts +1 -1
- package/dist/weixin/ilink-client.js +26 -1
- package/dist/weixin/ilink-client.js.map +1 -1
- package/dist/weixin/login.d.ts +3 -0
- package/dist/weixin/login.js +1 -1
- package/dist/weixin/login.js.map +1 -1
- package/package.json +9 -2
- package/dist/commerce/erp-source.d.ts +0 -51
- package/dist/commerce/erp-source.js +0 -184
- package/dist/commerce/erp-source.js.map +0 -1
- package/dist/commerce/local-db-source.d.ts +0 -50
- package/dist/commerce/local-db-source.js +0 -162
- package/dist/commerce/local-db-source.js.map +0 -1
package/README.md
CHANGED
|
@@ -90,6 +90,34 @@ kiwi> /negotiate cagt_... # 磋商 → agreement(无副作用)
|
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
> 注册域名默认 `merchant-<agent_id>.local`,可用 `KIWI_CATALOG_DOMAIN` 覆盖;catalog 地址默认 `http://127.0.0.1:8600`(`KIWI_CATALOG_URL` 覆盖)。
|
|
93
|
+
>
|
|
94
|
+
> **公网 merchant**:A2A 节点默认监听回环并广告回环地址(仅本机可达)。要让
|
|
95
|
+
> 外部 buyer 经 DNS + 反向代理(Caddy/Nginx)发现并直连,用
|
|
96
|
+
> `KIWI_A2A_PUBLIC_URL=https://<domain>`(如 `https://veyquo.com`)覆盖——
|
|
97
|
+
> 节点仍绑定 `127.0.0.1:<port>`,但 Agent Card / UCP / catalog 注册都广告该
|
|
98
|
+
> 公网 HTTPS 地址,注册域名缺省取 `<domain>`(`KIWI_CATALOG_DOMAIN` 仍优先)。
|
|
99
|
+
>
|
|
100
|
+
> **⚠️ 公网形态的认证前置条件(审查 BUG-02)**:广告地址非 loopback 时,节点
|
|
101
|
+
> **启动即失败**,除非显式配置入站认证验证器(`startA2aNode({authVerifier})`
|
|
102
|
+
> 或 `A2AServer` 的等价接线)。原因:缺省 `LoopbackOnlyAuthVerifier` 只信任
|
|
103
|
+
> socket 来源——反向代理从 `127.0.0.1` 连接节点,外部请求在应用层看起来就是
|
|
104
|
+
> loopback 并被认证通过,"仅本机可访问"的安全边界在公网形态下失效。
|
|
105
|
+
>
|
|
106
|
+
> 公网部署必须二选一:
|
|
107
|
+
> 1. **HTTP Message Signature 验证器**(推荐):`HttpMessageSignatureVerifier`
|
|
108
|
+
> 校验 RFC 9421 签名 + content-digest(带 body 的请求强制绑定请求体,
|
|
109
|
+
> 见 BUG-06),对端须持有本节点信任的签名密钥;
|
|
110
|
+
> 2. **明确、可审计的代理认证契约**:如反代层完成 TLS 客户端证书或等价强认证,
|
|
111
|
+
> 并把验证结果以节点可审计的方式透传——不得只信任 `remoteAddress`。
|
|
112
|
+
>
|
|
113
|
+
> 本地形态(不设 `KIWI_A2A_PUBLIC_URL`)不受影响,维持 loopback 默认值。
|
|
114
|
+
>
|
|
115
|
+
> `KIWI_A2A_AUTH` env 提供三种内置模式:`loopback`(**仅限本地开发 /
|
|
116
|
+
> 代理即边界**——节点只校验 socket 来源,经反代转发的公网流量在应用层
|
|
117
|
+
> 全部是 loopback 被放行,等价无应用层认证;公网广告地址 + loopback
|
|
118
|
+
> 启动时会输出醒目 stderr 警告)、`none`(显式可信网络/测试)、
|
|
119
|
+
> `bearer:<token>`(校验 `Authorization: Bearer <token>`,**公网节点
|
|
120
|
+
> 推荐**)。
|
|
93
121
|
|
|
94
122
|
### 真实商品闭环(shopping-cli 开放商品层)
|
|
95
123
|
|
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
# CandidateAgent DTO 1.0 — vendored contract
|
|
2
2
|
|
|
3
|
-
`candidate-agent-dto-1.0.schema.json` is
|
|
4
|
-
|
|
3
|
+
`candidate-agent-dto-1.0.schema.json` is the **normative wire contract** owned
|
|
4
|
+
by `kiwi/contracts` (contract **1.0**, draft-07). The Python DTO implementation
|
|
5
|
+
in `kiwi-catalog` is an implementation reference and must remain conformant.
|
|
5
6
|
|
|
6
7
|
## Source
|
|
7
8
|
|
|
8
9
|
| | |
|
|
9
10
|
|---|---|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
11
|
+
| Wire-contract authority | `kiwi/contracts/candidate-agent-dto-1.0.schema.json` |
|
|
12
|
+
| Implementation reference | `kiwi-catalog/kiwi_catalog/agent_catalog/candidate_dto.py` → `CANDIDATE_AGENT_SCHEMA` |
|
|
13
|
+
| Contract owner | `kiwi`(跨仓库契约权威) |
|
|
12
14
|
| Normative doc | `docs/a2a/candidate-agent-dto-1.0.md`(human-readable,字段语义) |
|
|
13
15
|
| Design intent | shopping-cli 设计 §8.2(Search Result Contract)、§21(AgentDiscovery Integration with Kiwi)、§22(Hosted/Direct Status Model) |
|
|
14
16
|
| `$id` | `urn:shopping-cli:candidate-agent:1.0` |
|
|
15
17
|
|
|
16
18
|
## Sync procedure
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
Changes to this file are contract changes and must be reviewed in `kiwi` first.
|
|
21
|
+
The catalog implementation is checked against this schema; it is not the source
|
|
22
|
+
of wire truth. To regenerate a compatibility fixture from the implementation:
|
|
19
23
|
|
|
20
24
|
```sh
|
|
21
|
-
cd /
|
|
25
|
+
cd /path/to/kiwi-catalog
|
|
22
26
|
python3 -c "import json,sys; sys.path.insert(0,'.'); \
|
|
23
|
-
from
|
|
27
|
+
from kiwi_catalog.agent_catalog.candidate_dto import CANDIDATE_AGENT_SCHEMA; \
|
|
24
28
|
print(json.dumps(CANDIDATE_AGENT_SCHEMA, indent=2, ensure_ascii=False))" \
|
|
25
|
-
> /
|
|
29
|
+
> /tmp/candidate-agent-dto-implementation.json
|
|
26
30
|
```
|
|
27
31
|
|
|
28
32
|
A schema change that adds/renames/removes a field, changes a type, narrows the
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Python service conformance kit (dev-only)
|
|
2
|
+
|
|
3
|
+
This directory is a test contract, not a production runtime dependency. Each
|
|
4
|
+
Python service supplies a tiny adapter exposing `apps(tmp_path)` with
|
|
5
|
+
`fallback` and `fastapi` application objects. The shared cases then exercise
|
|
6
|
+
only externally observable transport behavior.
|
|
7
|
+
|
|
8
|
+
The first gate covers malformed-body routing order, body-size rejection,
|
|
9
|
+
status/error envelopes, and secret non-reflection. Domain-specific auth,
|
|
10
|
+
idempotency, and SQLite migration behavior remains owned by each service until
|
|
11
|
+
two release cycles show that the semantics are genuinely identical.
|
|
12
|
+
|
|
13
|
+
Run from a portfolio composition checkout:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
PYTHONPATH=contracts/conformance/python-service:kiwi-catalog:shopping-cli \
|
|
17
|
+
python contracts/conformance/python-service/run.py \
|
|
18
|
+
kiwi_catalog_conformance:apps shopping_cli_conformance:apps
|
|
19
|
+
```
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Run the shared dev-only transport conformance cases for service adapters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import importlib
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
import tempfile
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Callable, Iterable, Protocol
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class Response:
|
|
17
|
+
status: int
|
|
18
|
+
headers: dict[str, str]
|
|
19
|
+
body: dict[str, Any]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Adapter(Protocol):
|
|
23
|
+
def apps(self, root: Path) -> dict[str, Any]: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _asgi_request(app: Any, method: str, path: str, *, headers: dict[str, str], body: bytes) -> Response:
|
|
27
|
+
sent: list[dict[str, Any]] = []
|
|
28
|
+
pending = [body]
|
|
29
|
+
|
|
30
|
+
async def receive() -> dict[str, Any]:
|
|
31
|
+
chunk = pending.pop(0) if pending else b""
|
|
32
|
+
return {"type": "http.request", "body": chunk, "more_body": bool(pending)}
|
|
33
|
+
|
|
34
|
+
async def send(message: dict[str, Any]) -> None:
|
|
35
|
+
sent.append(message)
|
|
36
|
+
|
|
37
|
+
async def run() -> None:
|
|
38
|
+
await app(
|
|
39
|
+
{
|
|
40
|
+
"type": "http",
|
|
41
|
+
"method": method,
|
|
42
|
+
"path": path,
|
|
43
|
+
"headers": [(k.lower().encode(), v.encode()) for k, v in headers.items()],
|
|
44
|
+
"query_string": b"",
|
|
45
|
+
},
|
|
46
|
+
receive,
|
|
47
|
+
send,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
asyncio.run(run())
|
|
51
|
+
start = next(item for item in sent if item["type"] == "http.response.start")
|
|
52
|
+
raw = b"".join(item.get("body", b"") for item in sent if item["type"] == "http.response.body")
|
|
53
|
+
return Response(
|
|
54
|
+
int(start["status"]),
|
|
55
|
+
{k.decode().lower(): v.decode() for k, v in start.get("headers", [])},
|
|
56
|
+
json.loads(raw.decode() or "{}"),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def request(app: Any, method: str, path: str, *, headers: dict[str, str], body: bytes) -> Response:
|
|
61
|
+
if type(app).__name__ == "FastAPI":
|
|
62
|
+
from fastapi.testclient import TestClient
|
|
63
|
+
|
|
64
|
+
with TestClient(app) as client:
|
|
65
|
+
result = client.request(method, path, headers=headers, content=body)
|
|
66
|
+
return Response(result.status_code, {k.lower(): v for k, v in result.headers.items()}, result.json())
|
|
67
|
+
return _asgi_request(app, method, path, headers=headers, body=body)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _assert_error(response: Response, status: int) -> None:
|
|
71
|
+
assert response.status == status, response
|
|
72
|
+
assert response.body.get("ok") is False, response
|
|
73
|
+
assert isinstance(response.body.get("error"), str), response
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def run_cases(factory: Callable[[Path], dict[str, Any]], paths: dict[str, str]) -> None:
|
|
77
|
+
with tempfile.TemporaryDirectory(prefix="kiwi-conformance-") as raw:
|
|
78
|
+
apps = factory(Path(raw))
|
|
79
|
+
assert set(apps) == {"fallback", "fastapi"}, apps
|
|
80
|
+
for stack, app in apps.items():
|
|
81
|
+
malformed = request(
|
|
82
|
+
app,
|
|
83
|
+
"POST",
|
|
84
|
+
"/no-such-route",
|
|
85
|
+
headers={"content-type": "application/json", "authorization": "Bearer conformance-secret"},
|
|
86
|
+
body=b"not-json",
|
|
87
|
+
)
|
|
88
|
+
_assert_error(malformed, 404)
|
|
89
|
+
assert "conformance-secret" not in json.dumps(malformed.body), (stack, malformed)
|
|
90
|
+
|
|
91
|
+
wrong_method = request(
|
|
92
|
+
app,
|
|
93
|
+
"DELETE",
|
|
94
|
+
paths["known_post"],
|
|
95
|
+
headers={"content-type": "application/json"},
|
|
96
|
+
body=b"not-json",
|
|
97
|
+
)
|
|
98
|
+
_assert_error(wrong_method, 405)
|
|
99
|
+
|
|
100
|
+
oversized = request(
|
|
101
|
+
app,
|
|
102
|
+
"POST",
|
|
103
|
+
paths["known_post"],
|
|
104
|
+
headers={"content-type": "application/json", "content-length": "2000000"},
|
|
105
|
+
body=b"{}",
|
|
106
|
+
)
|
|
107
|
+
_assert_error(oversized, 413)
|
|
108
|
+
|
|
109
|
+
exact_shape = request(
|
|
110
|
+
app,
|
|
111
|
+
"POST",
|
|
112
|
+
paths["known_post"],
|
|
113
|
+
headers={"content-type": "application/json"},
|
|
114
|
+
body=b"{}",
|
|
115
|
+
)
|
|
116
|
+
assert exact_shape.status in {400, 404}, (stack, exact_shape)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def main(argv: Iterable[str]) -> int:
|
|
120
|
+
specs = list(argv)
|
|
121
|
+
if not specs:
|
|
122
|
+
raise SystemExit("usage: run.py module:function [module:function ...]")
|
|
123
|
+
for spec in specs:
|
|
124
|
+
module_name, function_name = spec.split(":", 1)
|
|
125
|
+
module = importlib.import_module(module_name)
|
|
126
|
+
factory = getattr(module, function_name)
|
|
127
|
+
paths = getattr(module, "paths", lambda: {"known_post": "/products"})()
|
|
128
|
+
run_cases(factory, paths)
|
|
129
|
+
print(f"conformance passed: {spec}")
|
|
130
|
+
return 0
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -25,7 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"then": { "required": ["source_product_ref"] },
|
|
27
27
|
"else": {
|
|
28
|
-
"not": {
|
|
28
|
+
"not": {
|
|
29
|
+
"anyOf": [
|
|
30
|
+
{ "required": ["handoff_destination_types"] },
|
|
31
|
+
{ "required": ["handoff_destination_ref"] }
|
|
32
|
+
]
|
|
33
|
+
}
|
|
29
34
|
},
|
|
30
35
|
"properties": {
|
|
31
36
|
"listing_id": { "type": "string", "pattern": "^lst_" },
|
|
@@ -78,6 +83,11 @@
|
|
|
78
83
|
]
|
|
79
84
|
}
|
|
80
85
|
},
|
|
86
|
+
"handoff_destination_ref": {
|
|
87
|
+
"description": "每商品成交入口(KTH destination_ref):商家声明并维护的实际交易入口。URL 类(external_checkout_url 等)为 https URL;联系/会话类为 opaque ref。URL 安全性由 handoff 执行侧(url-safety)负责",
|
|
88
|
+
"type": "string",
|
|
89
|
+
"minLength": 1
|
|
90
|
+
},
|
|
81
91
|
"listing_digest": { "type": "string", "minLength": 1 },
|
|
82
92
|
"publication_state": { "enum": ["ACTIVE", "WITHDRAWN", "SUSPENDED"] },
|
|
83
93
|
"listing_freshness_state": { "enum": ["FRESH", "STALE"] },
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lock_version": 1,
|
|
3
|
+
"source_repository": "harrylabsj/kiwi",
|
|
4
|
+
"source_commit": "009bc25cdae2668c8fd19ccedcc4e0c64a34f6be",
|
|
5
|
+
"bundle_sha256": "2dbbc52a1113dc5c05dc544802571ee188b44e1567d6bfb0cd8ccd87ea7f4998",
|
|
6
|
+
"contracts_manifest": "contracts/manifest.json"
|
|
7
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": 1,
|
|
3
|
+
"authority": "kiwi/contracts",
|
|
4
|
+
"bundle_sha256": "2dbbc52a1113dc5c05dc544802571ee188b44e1567d6bfb0cd8ccd87ea7f4998",
|
|
5
|
+
"contracts": [
|
|
6
|
+
{
|
|
7
|
+
"id": "candidate-agent-dto",
|
|
8
|
+
"version": "1.0",
|
|
9
|
+
"path": "contracts/candidate-agent-dto-1.0.schema.json",
|
|
10
|
+
"sha256": "9c820cff1f998662dee6fe85f7a6a8bbc3d1a8bce8b8802b6483612ae06dec03"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "kiwi-catalog-agent-record",
|
|
14
|
+
"version": "1.0",
|
|
15
|
+
"path": "contracts/kiwi-catalog/1.0/agent-record.schema.json",
|
|
16
|
+
"sha256": "2d4cc595f8fd5d7bd6b7ce45066519695ecf867a3f1089bf112d1bff1e30fe15"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "kiwi-catalog-listing-record",
|
|
20
|
+
"version": "1.0",
|
|
21
|
+
"path": "contracts/kiwi-catalog/1.0/listing-record.schema.json",
|
|
22
|
+
"sha256": "9bdb2b262404b3a9fe57e4c4b09d337341d89f6b8aba40c54b49eaa46b687662"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "kiwi-catalog-listing-search-result",
|
|
26
|
+
"version": "1.0",
|
|
27
|
+
"path": "contracts/kiwi-catalog/1.0/listing-search-result.schema.json",
|
|
28
|
+
"sha256": "c77792ffb7e4eb0a59cd0f4d48059686face8878674afac1090808ccb6c7fee7"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "negotiation-envelope",
|
|
32
|
+
"version": "1.0",
|
|
33
|
+
"path": "contracts/negotiation/1.0/schema.json",
|
|
34
|
+
"sha256": "7a0da30fb8a6d91b653d9507beaa4615f263d4b26d7bc9c3e61f64853f3495c6"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "shopping-negotiation-capabilities",
|
|
38
|
+
"version": "0.1",
|
|
39
|
+
"path": "contracts/shopping.negotiation/0.1/capabilities.schema.json",
|
|
40
|
+
"sha256": "386a6eda04d20e31519e86aa2c7b30403af5ec31dbd9ac0d15a440347d7e1356"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "shopping-negotiation-decision",
|
|
44
|
+
"version": "0.1",
|
|
45
|
+
"path": "contracts/shopping.negotiation/0.1/decision.schema.json",
|
|
46
|
+
"sha256": "b98255cf779f76a15c5768dc75fd6d9cd5616c4cbaa0593053b113e7bd2c4ef1"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "shopping-negotiation-policy-result",
|
|
50
|
+
"version": "0.1",
|
|
51
|
+
"path": "contracts/shopping.negotiation/0.1/policy-result.schema.json",
|
|
52
|
+
"sha256": "3b2dd7980c091c50f8a58dd18f15a0a56a483ba722c075153ee1c3be07c660e8"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"id": "shopping-negotiation-snapshot",
|
|
56
|
+
"version": "0.1",
|
|
57
|
+
"path": "contracts/shopping.negotiation/0.1/snapshot.schema.json",
|
|
58
|
+
"sha256": "3684e5674917b1d3777e298d9e18e34f3f124d1ba7534540de08023be45a4e27"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"catalog_agent_id": "cagt_test_merchant_001",
|
|
3
|
+
"merchant": {
|
|
4
|
+
"id": "merchant-001",
|
|
5
|
+
"name": "Test Merchant",
|
|
6
|
+
"domain": "test.example"
|
|
7
|
+
},
|
|
8
|
+
"discovery": {
|
|
9
|
+
"agent_card_url": "https://test.example/.well-known/agent-card.json"
|
|
10
|
+
},
|
|
11
|
+
"protocols": {
|
|
12
|
+
"a2a": ["1.0.0"]
|
|
13
|
+
},
|
|
14
|
+
"capabilities": ["com.harrylabsj.kiwi.shopping.negotiation"],
|
|
15
|
+
"verification": {
|
|
16
|
+
"status": "discovered",
|
|
17
|
+
"last_verified_at": "2026-01-01T00:00:00Z"
|
|
18
|
+
},
|
|
19
|
+
"hosting": {
|
|
20
|
+
"mode": "direct_only"
|
|
21
|
+
},
|
|
22
|
+
"contract": {
|
|
23
|
+
"name": "candidate-agent",
|
|
24
|
+
"version": "1.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -91,47 +91,52 @@ export class A2AClient {
|
|
|
91
91
|
? baseHeaders
|
|
92
92
|
: { ...baseHeaders, ...this.signer.sign({ method: "POST", url: this.url.href, body: Buffer.from(body, "utf8"), headers: baseHeaders }) };
|
|
93
93
|
let response;
|
|
94
|
-
try {
|
|
95
|
-
response = await this.fetchImpl(this.url.href, {
|
|
96
|
-
method: "POST",
|
|
97
|
-
headers,
|
|
98
|
-
body,
|
|
99
|
-
// SSRF 防线:绝不跟随重定向——重定向目标不经过 SSRF/DNS 复查,且
|
|
100
|
-
// 3xx 可把请求体/认证头转发给第三方。resolve/ucp 已实施,本处对齐。
|
|
101
|
-
redirect: "manual",
|
|
102
|
-
signal: controller.signal,
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
if (controller.signal.aborted) {
|
|
107
|
-
throw new A2AClientError("timeout", `A2A request timed out after ${this.timeoutMs}ms`);
|
|
108
|
-
}
|
|
109
|
-
throw new A2AClientError("network", `A2A request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
110
|
-
}
|
|
111
|
-
if (isRedirectResponse(response)) {
|
|
112
|
-
throw new A2AClientError("http_status", `A2A endpoint must not redirect (HTTP ${response.status})`, { httpStatus: response.status });
|
|
113
|
-
}
|
|
114
94
|
let raw;
|
|
115
95
|
try {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
96
|
+
try {
|
|
97
|
+
response = await this.fetchImpl(this.url.href, {
|
|
98
|
+
method: "POST",
|
|
99
|
+
headers,
|
|
100
|
+
body,
|
|
101
|
+
// SSRF 防线:绝不跟随重定向——重定向目标不经过 SSRF/DNS 复查,且
|
|
102
|
+
// 3xx 可把请求体/认证头转发给第三方。resolve/ucp 已实施,本处对齐。
|
|
103
|
+
redirect: "manual",
|
|
104
|
+
signal: controller.signal,
|
|
105
|
+
});
|
|
123
106
|
}
|
|
124
|
-
|
|
125
|
-
|
|
107
|
+
catch (err) {
|
|
108
|
+
if (controller.signal.aborted) {
|
|
109
|
+
throw new A2AClientError("timeout", `A2A request timed out after ${this.timeoutMs}ms`);
|
|
110
|
+
}
|
|
111
|
+
throw new A2AClientError("network", `A2A request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
126
112
|
}
|
|
127
|
-
if (
|
|
128
|
-
throw new A2AClientError("http_status", `A2A HTTP ${response.status}
|
|
129
|
-
|
|
130
|
-
|
|
113
|
+
if (isRedirectResponse(response)) {
|
|
114
|
+
throw new A2AClientError("http_status", `A2A endpoint must not redirect (HTTP ${response.status})`, { httpStatus: response.status });
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
// 响应体读取在超时覆盖内(timer 活到 body 读完;对端停滞 body 也会
|
|
118
|
+
// 被 abort 中断),且有大小上限(防恶意对端回传 GB 级 body 打爆内存)。
|
|
119
|
+
raw = await readJsonBody(response, { signal: controller.signal });
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
if (controller.signal.aborted) {
|
|
123
|
+
throw new A2AClientError("timeout", `A2A request timed out after ${this.timeoutMs}ms`);
|
|
124
|
+
}
|
|
125
|
+
if (err instanceof SafeHttpError && err.code === "response_too_large") {
|
|
126
|
+
throw invalidResponse(err.message);
|
|
127
|
+
}
|
|
128
|
+
if (!response.ok) {
|
|
129
|
+
throw new A2AClientError("http_status", `A2A HTTP ${response.status} with non-JSON body`, {
|
|
130
|
+
httpStatus: response.status,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
throw invalidResponse("response body is not JSON");
|
|
131
134
|
}
|
|
132
|
-
throw invalidResponse("response body is not JSON");
|
|
133
135
|
}
|
|
134
136
|
finally {
|
|
137
|
+
// 审查 P2-02:所有路径(fetch 拒绝 / redirect / 非 2xx / body 读失败)
|
|
138
|
+
// 都必须清理超时 timer——此前只有 body 读的 finally 清理,fetch 抛错与
|
|
139
|
+
// redirect/非 2xx 的提前 throw 会泄漏存活 timer 与 AbortController。
|
|
135
140
|
clearTimeout(timer);
|
|
136
141
|
}
|
|
137
142
|
if (!response.ok) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/a2a/client/client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/a2a/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,8 +14,15 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
export interface SafeTargetUrlOptions {
|
|
17
|
-
/** 允许私网/保留网段(默认 false)。
|
|
17
|
+
/** 允许私网/保留网段(默认 false)。 */
|
|
18
18
|
allowPrivateRanges?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* 允许**静态字面** loopback 目标(localhost / 127.0.0.1 / ::1;本地开发默认
|
|
21
|
+
* true,不可信 Agent Card 应传 false)。只影响 assertSafeTargetUrl 的字面判定;
|
|
22
|
+
* assertResolvableTargetUrl 的 DNS 复查不读取本字段——公共主机名解析到 loopback
|
|
23
|
+
* 始终拒绝(DNS rebinding 不放宽)。
|
|
24
|
+
*/
|
|
25
|
+
allowLoopback?: boolean;
|
|
19
26
|
}
|
|
20
27
|
export declare function ipv4ToInt(ip: string): number | undefined;
|
|
21
28
|
export declare function isReservedIpv4(ip: string): {
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
* - 主机名先做保留主机名检查,再在请求前 DNS 解析复查解析出的 IP(DNS
|
|
26
26
|
* rebinding 的基础缓解;`allowPrivateRanges` 可显式逃生)。
|
|
27
27
|
*
|
|
28
|
+
* `allowLoopback` 只放宽**静态字面 loopback**(localhost / 127.0.0.1 / ::1,
|
|
29
|
+
* 由 assertSafeTargetUrl 判定)供本地开发;公共主机名解析到 loopback(DNS
|
|
30
|
+
* rebinding)与私网/保留网段始终拒绝,不因 `allowLoopback` / `allowPrivateRanges`
|
|
31
|
+
* 之外的任何开关放宽。
|
|
32
|
+
*
|
|
28
33
|
* 任何拒绝都抛 A2AClientError("unsafe_target"),fail-closed。
|
|
29
34
|
*/
|
|
30
35
|
import { lookup } from "node:dns/promises";
|
|
@@ -197,8 +202,12 @@ export function assertSafeTargetUrl(value, options = {}) {
|
|
|
197
202
|
throw unsafeTarget("cleartext HTTP only for loopback hosts (localhost, 127.0.0.1, ::1) — use HTTPS for remote endpoints");
|
|
198
203
|
}
|
|
199
204
|
}
|
|
200
|
-
if (loopback)
|
|
205
|
+
if (loopback) {
|
|
206
|
+
if (options.allowLoopback === false) {
|
|
207
|
+
throw unsafeTarget("A2A endpoint must not target loopback from an untrusted Agent Card");
|
|
208
|
+
}
|
|
201
209
|
return url;
|
|
210
|
+
}
|
|
202
211
|
if (isIpLiteral(hostname)) {
|
|
203
212
|
const ip = stripBrackets(hostname);
|
|
204
213
|
const check = isIP(ip) === 4 ? isReservedIpv4(ip) : isReservedIpv6(ip);
|
|
@@ -233,7 +242,14 @@ export async function assertResolvableTargetUrl(url, options = {}) {
|
|
|
233
242
|
for (const ip of ips) {
|
|
234
243
|
const version = isIP(ip);
|
|
235
244
|
const check = version === 4 ? isReservedIpv4(ip) : version === 6 ? isReservedIpv6(ip) : { reserved: false };
|
|
236
|
-
// loopback
|
|
245
|
+
// A public hostname that resolves to loopback is a DNS-rebinding SSRF
|
|
246
|
+
// target and must ALWAYS fail closed. `allowLoopback` only relaxes the
|
|
247
|
+
// *static* literal-loopback check in assertSafeTargetUrl (localhost /
|
|
248
|
+
// 127.0.0.1 / ::1) for local development; it never legitimizes a
|
|
249
|
+
// hostname→loopback mapping, and it never relaxes private/reserved ranges.
|
|
250
|
+
if (isLoopbackHost(ip) && !isLoopbackHost(hostname)) {
|
|
251
|
+
throw unsafeTarget(`A2A endpoint host ${hostname} resolves to loopback (${ip})`);
|
|
252
|
+
}
|
|
237
253
|
if (check.reserved && !isLoopbackHost(ip) && !options.allowPrivateRanges) {
|
|
238
254
|
throw unsafeTarget(`A2A endpoint host ${hostname} resolves to a reserved network (${check.name})`);
|
|
239
255
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-policy.js","sourceRoot":"","sources":["../../../src/a2a/client/url-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH
|
|
1
|
+
{"version":3,"file":"url-policy.js","sourceRoot":"","sources":["../../../src/a2a/client/url-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 现实单调时钟(审查 BUG-01):生产路径不得使用固定日期基准——此前
|
|
18
|
+
* node.ts / negotiate.ts 各自实现 monotonicNow,从固定 2026-08-07 起步、
|
|
19
|
+
* 每次调用只 +1ms。第三方会收到历史时间戳或已过期报价,本机又用同一假
|
|
20
|
+
* 时钟判断过期,形成"本机接受、外部拒绝"的互操作分裂;重启还会把时钟
|
|
21
|
+
* 重置回同一历史起点。
|
|
22
|
+
*
|
|
23
|
+
* 语义:返回墙钟 ISO 时间,但保证同进程内严格单调(max(墙钟, prev+1))——
|
|
24
|
+
* 同一毫秒的多个事件不会产生相同时间戳(ledger 内容去重依赖相同内容,
|
|
25
|
+
* 时间戳不参与去重键,但 created_at 必须与现实时间一致)。
|
|
26
|
+
*
|
|
27
|
+
* 测试可注入固定时间源:createMonotonicClock(() => Date.parse("..."))。
|
|
28
|
+
*/
|
|
29
|
+
/** 构造现实单调时钟:返回 ISO 字符串,同进程内严格递增。 */
|
|
30
|
+
export declare function createMonotonicClock(nowFn?: () => number): () => string;
|