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
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,28 @@ console.log(receipt.invocationId, receipt.status, receipt.chargedUsdc);

TypeScript does not read environment variables by itself. Read them in your app and pass `environment` or `gatewayUrl` explicitly.

### LLM token-metered calls

LLM services registered with `serviceKind=llm` and `priceModel=token_metered` use `invoke_llm()` / `invokeLlm()`. Do not pass `cost_usdc` / `costUsdc`; pass optional `max_cost_usdc` / `maxCostUsdc` or let Gateway compute the automatic hold. Streaming is rejected in V1 so Gateway can capture final usage safely.

```python
result = client.invoke_llm(
"svc_deepseek_chat",
{"messages": [{"role": "user", "content": "hello"}], "max_tokens": 512},
max_cost_usdc="0.010000",
)
print(result.usage.input_tokens, result.synapse.charged_usdc, result.synapse.released_usdc)
```

```ts
const result = await client.invokeLlm(
"svc_deepseek_chat",
{ messages: [{ role: "user", content: "hello" }], max_tokens: 512 },
{ maxCostUsdc: "0.010000" }
);
console.log(result.usage?.inputTokens, result.synapse?.chargedUsdc, result.synapse?.releasedUsdc);
```

## Advanced: Programmatic Credential Issuance

Use `SynapseAuth` only when an owner/backend service needs to issue credentials or register provider services programmatically. Ordinary agent runtime code should use `SynapseClient` with an existing `agt_xxx` key.
Expand Down Expand Up @@ -274,6 +296,8 @@ Supported today:
- Provider service register/list/get/status/update/delete/ping/registration guide/health history
- Provider earnings and withdrawal intent/list/capability helpers

Public owner/provider helpers return named SDK objects such as `UsageLogList`, `ProviderRegistrationGuide`, and `ProviderWithdrawalIntentResult`, not raw maps.

Not yet wrapped:

- Refunds, notifications, community, and event APIs
Expand Down
24 changes: 24 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,28 @@ console.log(receipt.invocationId, receipt.status, receipt.chargedUsdc);

TypeScript SDK 不会自动读取环境变量。请在你的应用中读取环境变量,然后显式传入 `environment` 或 `gatewayUrl`。

### LLM 按 token 计费调用

使用 `serviceKind=llm` 和 `priceModel=token_metered` 注册的 LLM 服务,需要调用 `invoke_llm()` / `invokeLlm()`。不要传 `cost_usdc` / `costUsdc`;可以传可选的 `max_cost_usdc` / `maxCostUsdc`,也可以交给 Gateway 自动冻结。V1 会拒绝 streaming,确保 Gateway 能拿到 final usage 后再扣费。

```python
result = client.invoke_llm(
"svc_deepseek_chat",
{"messages": [{"role": "user", "content": "hello"}], "max_tokens": 512},
max_cost_usdc="0.010000",
)
print(result.usage.input_tokens, result.synapse.charged_usdc, result.synapse.released_usdc)
```

```ts
const result = await client.invokeLlm(
"svc_deepseek_chat",
{ messages: [{ role: "user", content: "hello" }], max_tokens: 512 },
{ maxCostUsdc: "0.010000" }
);
console.log(result.usage?.inputTokens, result.synapse?.chargedUsdc, result.synapse?.releasedUsdc);
```

## 高级用法:以代码方式签发凭据

只有当 owner/backend service 需要以代码方式签发凭据或注册 provider service 时,才使用 `SynapseAuth`。普通 Agent 运行时代码应使用已有 `agt_xxx` key 和 `SynapseClient`。
Expand Down Expand Up @@ -274,6 +296,8 @@ PYTHONPATH="$PWD" .venv/bin/python examples/consumer_wallet_to_invoke.py \
- Provider service register/list/get/status/update/delete/ping/registration guide/health history
- Provider earnings and withdrawal intent/list/capability helpers

公开 owner/provider helper 返回 `UsageLogList`、`ProviderRegistrationGuide`、`ProviderWithdrawalIntentResult` 等命名 SDK 对象,而不是 raw map。

尚未封装:

- Refunds、notifications、community、event APIs
Expand Down
13 changes: 10 additions & 3 deletions docs/agent-map/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"SECURITY.md",
"docs/sdk/README.md",
"docs/sdk/capability_inventory.md",
"docs/quality-gates.md",
"scripts/ci/pr_checks.sh"
],
"domains": [
Expand Down Expand Up @@ -70,7 +71,8 @@
],
"notes": [
"Credential and finance-adjacent helpers must not log real tokens or secrets.",
"High-impact finance helpers may wrap API calls, but should not auto-execute irreversible user actions."
"High-impact finance helpers may wrap API calls, but should not auto-execute irreversible user actions.",
"Public owner-auth returns must use named SDK models/interfaces, not raw dict or Record."
]
},
{
Expand Down Expand Up @@ -98,7 +100,8 @@
],
"notes": [
"Provider onboarding success is measured through owner control-plane service records, not public discovery alone.",
"Provider is an owner-scoped supply-side role; use auth.provider() / SynapseProvider rather than a separate root identity."
"Provider is an owner-scoped supply-side role; use auth.provider() / SynapseProvider rather than a separate root identity.",
"Public provider facade returns must use named SDK models/interfaces, not raw dict or Record."
]
},
{
Expand Down Expand Up @@ -179,6 +182,9 @@
"scripts/ci/python_checks.sh",
"scripts/ci/typescript_checks.sh",
"scripts/ci/repo_hygiene_checks.sh",
"scripts/ci/security_checks.sh",
"scripts/ci/source_quality_checks.py",
"docs/quality-gates.md",
"typescript/package.json"
],
"supporting_files": [
Expand All @@ -189,7 +195,8 @@
"bash scripts/ci/pr_checks.sh"
],
"notes": [
"Local scripts and GitHub Actions must share the same entrypoint."
"Local scripts and GitHub Actions must share the same entrypoint.",
"Source files over 500 lines, high complexity, and duplicate code above threshold must fail PR CI."
]
},
{
Expand Down
37 changes: 26 additions & 11 deletions docs/plans/bootstrap-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,42 @@

- Project: `synapse-network-sdk`
- Root: `/Users/cliff/workspace/agent/Synapse-Network-Sdk`
- Overall: `READY`
- Overall: `PARTIAL`

## Checklist
- [x] Core - Core status=HEALTHY (ok=7, warn=0, fail=0, info=0)
- [ ] Core - Core status=ATTENTION (ok=6, warn=0, fail=1, info=0)
- [x] Planning - Planning status=HEALTHY (ok=2, warn=0, fail=0, info=0)
- [x] Integration - Integration status=HEALTHY (ok=2, warn=0, fail=0, info=0)
- [ ] Optional - Optional status=WATCH (ok=2, warn=5, fail=0, info=0)
- [x] Final verification - latest `amem doctor .` already reflects the current healthy state
- [ ] Final verification - re-run `amem doctor .` and confirm no remaining WARN / FAIL steps

## Action Sequence
1. Optional (recommended): Refactor flagged functions before adding more behavior, and add a short guiding comment when complex logic must remain in place.
1. Core (required): Re-run `amem profile-check .` and repair the missing profile-managed files.
2. Optional (recommended): Refactor flagged functions before adding more behavior, and add a short guiding comment when complex logic must remain in place.

## Onboarding Runbook
### Step 1: Core / profile_consistency
- Priority: `required`
- Trigger: missing required file: tests
- Action: Repair missing or drifted profile-managed files before continuing onboarding.
- Command: `amem profile-check .`
- Verify with: `amem profile-check .`
- Next command: `amem doctor .`
- Safe To Auto Execute: `False`
- Approval Required: `True`
- Approval Reason: this step diagnoses drift but manual repair choices still require a human decision
- Done when: `amem doctor .` shows `[OK] profile_consistency`.

## Group Health
### Core
- Summary: Core status=HEALTHY (ok=7, warn=0, fail=0, info=0)
- Summary: Core status=ATTENTION (ok=6, warn=0, fail=1, info=0)
- [OK] `registry` registered as 'synapse-network-sdk'
- [OK] `active` active=true
- [OK] `root` /Users/cliff/workspace/agent/Synapse-Network-Sdk
- [OK] `python3.12` /opt/homebrew/bin/python3.12
- [OK] `mcp_package` mcp import OK
- [OK] `profile_manifest` applied profile 'python-service'
- [OK] `profile_consistency` profile 'python-service' consistency OK
- [FAIL] `profile_consistency` missing required file: tests

### Planning
- Summary: Planning status=HEALTHY (ok=2, warn=0, fail=0, info=0)
Expand All @@ -38,8 +53,8 @@
- Summary: Optional status=WATCH (ok=2, warn=5, fail=0, info=0)
- [OK] `copilot_activation` Agents-Memory activation block present -> /Users/cliff/workspace/agent/Synapse-Network-Sdk/.github/copilot-instructions.md
- [OK] `agents_read_order` AGENTS.md references current bridge and 8 managed standard(s)
- [WARN] `refactor_watch` python/examples/smoke_test.py::main high complexity (lines=101>40, locals=12>8, branches=5, missing_guiding_comment)
- [WARN] `refactor_watch` python/synapse_client/test/test_consumer_e2e.py::test_python_sdk_consumer_cold_start_e2e high complexity (lines=134>40, locals=30>8, missing_guiding_comment)
- [WARN] `refactor_watch` python/synapse_client/test/test_consumer_e2e.py::_fund_and_deposit high complexity (lines=57>40, locals=15>8, missing_guiding_comment)
- [WARN] `refactor_watch` python/synapse_client/test/test_consumer_e2e.py::test_python_sdk_credential_management_e2e high complexity (lines=75>40, locals=25>8)
- [WARN] `refactor_watch` python/synapse_client/auth.py::SynapseAuth.issue_credential high complexity (branches=7>5, lines=38, locals=8, missing_guiding_comment)
- [WARN] `refactor_watch` python/examples/consumer_wallet_to_invoke.py::main high complexity (lines=78>40, branches=7>5, locals=18>8, nesting=3, missing_guiding_comment)
- [WARN] `refactor_watch` python/examples/smoke_test.py::main high complexity (lines=104>40, branches=6>5, locals=13>8, missing_guiding_comment)
- [WARN] `refactor_watch` python/examples/consumer_call_provider.py::main high complexity (lines=42>40, locals=10>8, branches=4, missing_guiding_comment)
- [WARN] `refactor_watch` python/synapse_client/test/test_consumer_e2e.py::test_python_sdk_consumer_cold_start_e2e high complexity (lines=135>40, locals=30>8, missing_guiding_comment)
- [WARN] `refactor_watch` python/examples/provider_staging_onboarding.py::main high complexity (lines=46>40, locals=9>8, missing_guiding_comment)
32 changes: 16 additions & 16 deletions docs/plans/refactor-watch.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ Track Python functions that are already high-complexity or are approaching the c

## Hotspots

1. [WARN] `python/examples/smoke_test.py::main` line=376 metrics=(lines=101, branches=5, nesting=2, locals=12)
1. [WARN] `python/examples/consumer_wallet_to_invoke.py::main` line=74 metrics=(lines=78, branches=7, nesting=3, locals=18)
- token: `hotspot-664c48761084`
- issues: `lines=78>40, branches=7>5, locals=18>8, nesting=3, missing_guiding_comment`
- bundle command: `amem refactor-bundle . --token hotspot-664c48761084`
2. [WARN] `python/examples/smoke_test.py::main` line=345 metrics=(lines=104, branches=6, nesting=2, locals=13)
- token: `hotspot-8ec9b16a0f08`
- issues: `lines=101>40, locals=12>8, branches=5, missing_guiding_comment`
- issues: `lines=104>40, branches=6>5, locals=13>8, missing_guiding_comment`
- bundle command: `amem refactor-bundle . --token hotspot-8ec9b16a0f08`
2. [WARN] `python/synapse_client/test/test_consumer_e2e.py::test_python_sdk_consumer_cold_start_e2e` line=175 metrics=(lines=134, branches=0, nesting=0, locals=30)
3. [WARN] `python/examples/consumer_call_provider.py::main` line=116 metrics=(lines=42, branches=4, nesting=2, locals=10)
- token: `hotspot-c6270384bbbf`
- issues: `lines=42>40, locals=10>8, branches=4, missing_guiding_comment`
- bundle command: `amem refactor-bundle . --token hotspot-c6270384bbbf`
4. [WARN] `python/synapse_client/test/test_consumer_e2e.py::test_python_sdk_consumer_cold_start_e2e` line=174 metrics=(lines=135, branches=0, nesting=0, locals=30)
- token: `hotspot-402833792f1b`
- issues: `lines=134>40, locals=30>8, missing_guiding_comment`
- issues: `lines=135>40, locals=30>8, missing_guiding_comment`
- bundle command: `amem refactor-bundle . --token hotspot-402833792f1b`
3. [WARN] `python/synapse_client/test/test_consumer_e2e.py::_fund_and_deposit` line=77 metrics=(lines=57, branches=0, nesting=0, locals=15)
- token: `hotspot-7f5cb8d7d075`
- issues: `lines=57>40, locals=15>8, missing_guiding_comment`
- bundle command: `amem refactor-bundle . --token hotspot-7f5cb8d7d075`
4. [WARN] `python/synapse_client/test/test_consumer_e2e.py::test_python_sdk_credential_management_e2e` line=327 metrics=(lines=75, branches=1, nesting=1, locals=25)
- token: `hotspot-26c3a2e1a320`
- issues: `lines=75>40, locals=25>8`
- bundle command: `amem refactor-bundle . --token hotspot-26c3a2e1a320`
5. [WARN] `python/synapse_client/auth.py::SynapseAuth.issue_credential` line=198 metrics=(lines=38, branches=7, nesting=2, locals=8)
- token: `hotspot-4ede4034d9f9`
- issues: `branches=7>5, lines=38, locals=8, missing_guiding_comment`
- bundle command: `amem refactor-bundle . --token hotspot-4ede4034d9f9`
5. [WARN] `python/examples/provider_staging_onboarding.py::main` line=91 metrics=(lines=46, branches=2, nesting=1, locals=9)
- token: `hotspot-41fb390a7399`
- issues: `lines=46>40, locals=9>8, missing_guiding_comment`
- bundle command: `amem refactor-bundle . --token hotspot-41fb390a7399`

## Suggested Action

Expand Down
42 changes: 42 additions & 0 deletions docs/quality-gates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
created_at: 2026-04-28
updated_at: 2026-04-28
doc_status: active
---

# SDK Quality Gates

This repository uses `bash scripts/ci/pr_checks.sh` as the single PR quality gate entrypoint. GitHub Actions and local validation must keep using that same script so PR behavior matches developer machines.

## Required Checks

- Repo hygiene: retired gateway domains, deprecated brand wording, README language split, staging defaults, and sensitive tracked filenames.
- Python: Ruff format, Ruff lint, Mypy, unit tests with coverage, source size checks, Radon cyclomatic complexity, and package build.
- TypeScript: Prettier, ESLint, `tsc --noEmit`, package build, unit tests, coverage, and duplicate-code scanning.
- Security: Bandit for Python source and `npm audit --omit=dev --audit-level=high` for production npm dependencies.

## Thresholds

- Source files must be `500` lines or fewer.
- Test files may be up to `700` lines while the suite is being decomposed.
- Python functions may have at most `40` effective logic lines.
- Python Radon complexity must stay at grade `A` or `B`; grade `C` or worse fails CI.
- TypeScript ESLint complexity must be `8` or lower.
- TypeScript functions may have at most `60` effective lines.
- Python coverage must be at least `80%`.
- TypeScript global lines, branches, functions, and statements coverage must each be at least `80%`.
- Duplicate code across `python/synapse_client` and `typescript/src` must stay at or below `3%` with a `50` token minimum clone size.
- Public `SynapseAuth` and `SynapseProvider` methods must return named SDK models/interfaces, never raw Python `dict` or TypeScript `Record<string, unknown>`. Internal HTTP payloads, schemas, and patch inputs may remain map-shaped.

## Refactor Rules

- If a source file exceeds `500` lines, split it before adding more behavior.
- If logic appears in three places, extract a shared helper or module.
- If a function exceeds `40` Python effective lines, `60` TypeScript lines, or the complexity threshold, split pure decisions from I/O and orchestration.
- Bug fixes need regression tests. New observable behavior needs unit tests.
- New owner/provider SDK methods need a named result model/interface before they are exposed publicly.
- Public SDK API changes must update docs and `docs/sdk/capability_inventory.md` when the implementation state changes.

## GitHub Enforcement

The `main` branch must require the PR CI status check named `SDK PR quality gates`, require the branch to be up to date, block direct pushes, and require at least one approving review before merge.
9 changes: 7 additions & 2 deletions docs/sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ The SDK currently has three explicit public surfaces:

Provider remains an owner-scoped supply-side role. `SynapseProvider` improves discoverability but does not introduce a second provider root identity.

Python quote-first methods `create_quote()`, `create_invocation()`, and `invoke_service()` are deprecated. They no longer call old endpoints and instead tell users to use discovery/search + `invoke(..., cost_usdc=...)`.
Owner/provider helper returns are typed SDK objects. Do not document or add public `SynapseAuth` / `SynapseProvider` methods that return raw Python `dict` or TypeScript `Record<string, unknown>`; add a named result model/interface instead.

Python quote-first methods `create_quote()`, `create_invocation()`, and `invoke_service()` are deprecated. They no longer call old endpoints and instead tell users to use discovery/search + `invoke(..., cost_usdc=...)` for fixed-price APIs.

LLM services use `serviceKind=llm` + `priceModel=token_metered`. Runtime code should call `invoke_llm()` / `invokeLlm()` and read `usage` plus `synapse` billing metadata. Do not pass `cost_usdc` / `costUsdc` for LLM calls; pass optional `max_cost_usdc` / `maxCostUsdc` or let Gateway compute the automatic hold. Streaming is disabled in V1.

## Staging Docs

Expand Down Expand Up @@ -95,7 +99,8 @@ Runtime calls should include:

1. `request_id` / request header for gateway log correlation.
2. `idempotency_key` / `idempotencyKey` to avoid duplicate charges or duplicate execution.
3. `cost_usdc` / `costUsdc` from latest discovery price. If price changes, the gateway rejects the call and the caller should rediscover.
3. For fixed-price APIs, pass `cost_usdc` / `costUsdc` from latest discovery price. If price changes, the gateway rejects the call and the caller should rediscover.
4. For token-metered LLM services, call `invoke_llm()` / `invokeLlm()` with optional `max_cost_usdc` / `maxCostUsdc`; final Provider `usage` drives the actual charge.

## Common Failures

Expand Down
9 changes: 7 additions & 2 deletions docs/sdk/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ SDK 当前有三个明确的公开入口:

Provider 仍然是 owner scope 下的供给侧角色。`SynapseProvider` 只是让 provider 接入更容易发现,不引入第二套 provider root 身份。

Python 旧的 quote-first 方法 `create_quote()`、`create_invocation()`、`invoke_service()` 已经废弃。它们不会再访问旧 endpoint,而是直接提示改用 discovery/search + `invoke(..., cost_usdc=...)`。
Owner/provider helper 的返回值必须是命名 SDK 对象。不要新增或记录返回 raw Python `dict` / TypeScript `Record<string, unknown>` 的公开 `SynapseAuth` / `SynapseProvider` 方法;应先新增命名 result model/interface。

Python 旧的 quote-first 方法 `create_quote()`、`create_invocation()`、`invoke_service()` 已经废弃。它们不会再访问旧 endpoint,而是直接提示普通 fixed-price API 改用 discovery/search + `invoke(..., cost_usdc=...)`。

LLM 服务使用 `serviceKind=llm` + `priceModel=token_metered`。Runtime 代码应调用 `invoke_llm()` / `invokeLlm()`,并读取返回里的 `usage` 与 `synapse` 计费元数据。LLM 调用不要传 `cost_usdc` / `costUsdc`;可以传可选的 `max_cost_usdc` / `maxCostUsdc`,也可以交给 Gateway 自动冻结。V1 禁用 streaming。

## Staging 产品文档

Expand Down Expand Up @@ -95,7 +99,8 @@ TypeScript:

1. `request_id` / request header,用于串联 gateway 日志。
2. `idempotency_key` / `idempotencyKey`,用于避免重复扣费或重复执行。
3. `cost_usdc` / `costUsdc`,来自最新 discovery price。若价格变化,gateway 会拒绝本次调用,调用方应重新 discovery。
3. 普通 fixed-price API 传 `cost_usdc` / `costUsdc`,来自最新 discovery price。若价格变化,gateway 会拒绝本次调用,调用方应重新 discovery。
4. 按 token 计费的 LLM 服务调用 `invoke_llm()` / `invokeLlm()`,可选传 `max_cost_usdc` / `maxCostUsdc`;最终按 Provider 返回的 `usage` 精准扣费。

## 常见故障

Expand Down
Loading
Loading