Ctrl K
ComunidadGuías…

docs/SDK.en.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# SDK Guide

BailingHub SDKs are helper libraries for business systems.

They do six things:

1. generate OpenAPI tool specs
2. verify signed tool calls from the hub
3. verify delivery callbacks
4. sign authenticated visitor tickets for the web widget
5. implement authorization-probe helpers
6. call hub APIs such as `/run`, `/jobs/{id}`, and `/send`

The SDK is a convenience layer. The stable contract is still OpenAPI + `x-agent-capability` metadata + HMAC signatures.

## Available SDKs

| Runtime | Path | Purpose |
|---|---|---|
| PHP 8+ | `sdk/php` | Attribute-based tool declarations and signature helpers. |
| PHP 7.3+ | `sdk/php7` | Builder-style tool declarations for older PHP projects. |
| Node.js | `sdk/node` | `buildOpenApiSpec`, `tool`, `param`, `signTicket`, `HubClient`, verification helpers. |
| Python | `sdk/python` | `build_openapi_spec`, `tool`, `param`, `sign_ticket`, `HubClient`, verification helpers. |
| Java 11+ | `sdk/java` | Standard-library SDK for JVM business services. |
| Go 1.21+ | `sdk/go` | Standard-library SDK for Go services and gateways. |
| .NET 8+ | `sdk/dotnet` | Standard-library SDK for C# business services. |

## Common Helper Surface

The exact method names follow each language's style, but every official SDK should cover the same surface:

| Capability | PHP | Node | Python | Java / Go / .NET |
|---|---|---|---|---|
| Tool spec | annotations / builder | `buildOpenApiSpec` | `build_openapi_spec` | `BuildOpenApiSpec` / `BuildOpenAPISpec` |
| Visitor ticket | `Ticket::sign` | `signTicket` | `sign_ticket` | `signTicket` / `SignTicket` |
| Tool call verification | `Verify::gate` / `Verify::toolCall` | `verifyToolCall` | `verify_tool_call` | `verifyToolCall` / `VerifyToolCall` |
| Callback verification | `Verify::callback` | `verifyCallback` | `verify_callback` | `verifyCallback` / `VerifyCallback` |
| Authz probe | `SpecServer::authzProbe` | `authzProbeResponse` | `authz_probe_response` | `authzProbeResponse` / `AuthzProbeResponse` |
| PHP spec serving | `SpecServer::handle` / `respond` / `handlePublic` / `respondPublic` | — | — | — |
| Hub APIs | `HubClient` | `HubClient` | `HubClient` | `HubClient` |

## PHP Spec Endpoint Security

Pass the tool-provider secret to `SpecServer::handle()` or `respond()` for a
signed-only spec endpoint. Bare PHP `respond()` automatically emits
`Cache-Control: private, no-store`; framework integrations should apply
`SpecServer::responseHeaders($secret)` to the returned response.

The console exposes exactly two catalog policies: `signed_required` for the
protected form above and `public_allowed` for an intentionally public catalog.
For the latter, use `SpecServer::handlePublic()` or
`SpecServer::respondPublic()`. The
older `null` secret argument remains compatible, but the explicit helper keeps
the security decision visible in code. Public catalog access never makes tool
calls public: every tool call still requires signature verification and the
business system's on-behalf-of authorization.

## Node Example

```js
import { buildOpenApiSpec, param, tool } from '@bailinghub/connect';

const spec = buildOpenApiSpec({
  title: 'CRM Tools',
  version: '1.0.0',
  authzProbe: { method: 'POST', path: '/.well-known/bailing/authz-probe' },
  tools: [
    tool({
      name: 'member_query',
      method: 'GET',
      path: '/api/members/{id}',
      description: 'Query member profile',
      scope: 'member.read',
      requiresSubject: true,
      params: [param('id', { in: 'path', required: true, description: 'Member ID' })],
    }),
  ],
});

console.log(JSON.stringify(spec, null, 2));
```

Verify a tool call:

```js
import { verifyToolCall } from '@bailinghub/connect';

const ok = verifyToolCall(process.env.BAILING_TOOL_SECRET, {
  method: request.method,
  pathWithQuery,
  body: rawBody,
  timestamp: request.headers.get('x-bailing-timestamp'),
  signature: request.headers.get('x-bailing-signature'),
  onBehalfOf: request.headers.get('x-bailing-on-behalf-of') || '',
  jobId: request.headers.get('x-bailing-job-id') || '',
});
```

After verification, still check your own permission table.

## Python Example

```python
from bailing_connect import build_openapi_spec, param, tool

spec = build_openapi_spec(
    title="CRM Tools",
    version="1.0.0",
    authz_probe={"method": "POST", "path": "/.well-known/bailing/authz-probe"},
    tools=[
        tool(
            name="member_query",
            method="GET",
            path="/api/members/{id}",
            description="Query member profile",
            scope="member.read",
            requiresSubject=True,
            params=[param("id", **{"in": "path", "required": True, "description": "Member ID"})],
        )
    ],
)
```

## Hub Client Example

The hub client is a thin wrapper over the stable HTTP contract:

```js
import { HubClient } from '@bailinghub/connect';

const hub = new HubClient({ baseUrl: 'https://hub.example.com', token: process.env.BAILING_CLIENT_TOKEN });

const job = await hub.run({
  requestId: 'crm_1001',
  route: 'member-support',
  input: 'Check member recharge records',
  metadata: { principal: { id: 'u1001', tenant: 't1' } },
});

const result = await hub.getJob(job.job_id);
await hub.send({ requestId: 'notice_1001', channel: 'team-im', to: 'user_001', text: 'Task completed' });
```

## PHP 8+ Example

```php
#[AiTool(
    description: 'Query member profile',
    name: 'member_query',
    scope: 'member.read',
    path: '/api/members/query',
    method: 'POST',
    readonly: true,
    idempotent: true,
    sensitive: true,
    requiresSubject: true,
)]
#[AiParam('mobile', description: 'Member mobile phone', required: true, format: 'phone')]
public function memberQuery(): void
{
}
```

## Agent authorization lifecycle (Core 0.7.0)

PHP 8.1+ and PHP 7.3 provide the optional server-side `AgentAuth` helper for browser consent.
The additions in this branch let the business backend find the device session created by an
authorization and withdraw access when a device is lost or an operator leaves. They require
Core 0.7.0 and the matching PHP/PHP7 SDK bundles. Core 0.6.1 does not include these lifecycle methods.

```php
$auth = new \Bailing\Connect\AgentAuth('https://hub.example.com', $clientToken);
$page = $auth->listSessions(['tenant' => (string) $tenantId, 'limit' => 20]);
$context = $auth->context($authorizationId); // Existing fields plus session on consumed records.
$result = $auth->revokeAuthorization($authorizationId);
```

Only the current Client App is queried. The backend must also authorize its caller to manage the
requested tenant or operator. An operator filter requires `principal_id` and `tenant`; an empty
tenant explicitly selects a tenantless identity. Pass an opaque `next_cursor` with the original
filters until it is null; pages reflect current state rather than a frozen snapshot.
Expiry follows the refresh/session lifetime, and `active` is not proof of current business access.
Missing session mappings must not be inferred. Revocation is idempotent for the same authorization;
a timeout/503 or a consumed record's missing-mapping 404 must not be reported as success.
`revokeSession()` remains available for a known Session ID, and Client Tokens stay server-side.

Node and Python currently have no separate `AgentAuth` helper. Use the same backend HTTP contract
without introducing another authorization protocol. See [Agent Auth v1](AGENT_AUTH_API.en.md)
and the [integration quickstart](AGENT_CLIENT_QUICKSTART.en.md).

## Contract Test

All SDKs are validated against the same tool contract:

```bash
npm run sdk:test
npm run sdk:test7
npm run sdk:test-node
npm run sdk:test-python
npm run sdk:test-runtime
npm run sdk:test-p1
```

These tests build SDK-generated specs, compile them through the hub's OpenAPI tool compiler, verify runtime helpers across PHP/Node/Python, and compile or source-check the Java/Go/.NET SDKs depending on the local toolchain.

The runtime checks use `php` by default for both PHP source variants. Set
`BAILING_SDK_PHP7_BINARY` to a real PHP 7.3/7.4 executable to verify that interpreter; running the
PHP 7-compatible source on PHP 8 does not establish PHP 7 runtime coverage.