Metadata-Version: 2.5
Name: ikc-open-platform-sdk
Version: 0.6.1
Summary: ikc-open-platform 第三方开发者 SDK：API Key 认证 + 统一壳解包 + 四类业务域（知识库/文档/解析/检索）+ Wiki/图谱子资源 + 本体域（Ontology，O-01~O-24）+ 记忆域（Flash Knowledge），业务模型复用 ikc-sdk-lib
Author: SITECH-iKM
Requires-Python: >=3.12
Requires-Dist: httpx<1.0,>=0.27
Requires-Dist: ikc-sdk-lib==0.18.0
Requires-Dist: pydantic<3.0,>=2.7
Description-Content-Type: text/markdown

# ikc-open-platform-sdk

ikc-open-platform 第三方开发者 SDK（导入包 `ikc_open_platform_sdk`）。

- 认证：应用 API Key（`Authorization: Bearer <api-key>`，由管理面 `/admin/apps/{appId}/keys` 创建）。
- 协议：统一响应壳 `errCode/errMsg/data/traceId/reqId` 解包；业务模型一律复用 `ikc-sdk-lib`（本 SDK 不自定义业务模型）。
- 追踪：每请求注入 23 位纯数字 `X-Request-Id`；`reqId` 可显式传入，缺省 SDK 生成 `req_` 前缀值并随壳回显。
- 能力面（四类业务域 + 知识库子资源域 Wiki / 图谱 + 记忆域 Flash Knowledge）：
  - `client.knowledge_bases`：create / update / query / get
  - `client.documents`：ingest / ingest_and_parse / upload / get
  - `client.parse`：parse / parse_direct / query_result / issue_download_ticket / download
  - `client.search`：universal_search（V1）/ universal_search_v2（V2）/ deep_search / query（兼容别名）
  - `client.wiki`：tree / page / stat / export / build / job（W-01/W-02/W-04/W-05 只读 + W-06/W-07 构建）
    + 人工修正（W-08~W-19 写面）：page_patch / page_create / page_move / page_merge / page_split /
      page_retire / page_restore / sources_patch / links_patch / corrections_apply /
      revisions / revision / revision_revert / submit_review / reviews / review_action
  - `client.graph`：stat / nodes / edges / export / build / job（G-01/G-02/G-03/G-05 只读 + G-06/G-07 构建）
    + 检索 / 结构（G-04，2026-10-06 起 core 读自己的库并开放北向）：neighbors（1/2 跳邻域）/
      paths（两实体最短路径）/ search（图内词法检索；`ikc-sdk-lib` 尚无响应模型，返回原始 `data` dict）
  - `client.flash`：observe / write / recall / query / get / update / delete / consolidate / job / jobs / policy（记忆域 M-01~M-11；面向 agent 的短期 / 长期记忆）
- 错误模型：`OpenPlatformAPIError`（errCode/errMsg/traceId/reqId）、`OpenPlatformConnectionError`、`OpenPlatformTimeoutError`、`OpenPlatformProtocolError`。
- 响应校验：W/G 域按 `ikc_sdk.core.api.{wiki,graph}.*`、记忆域按 `ikc_sdk.flash.api` 模型校验；**实例侧字段漂移时记 warning 并回落原始 `dict`**，
  不因契约模型过严打断调用。模型本身的缺陷回 `ikc-sdk-lib` 修（先例：W-02 `page.unitId` 实测为 `null`，
  `ikc-sdk-lib` 0.9.2 已把 `WikiPageView.unitId` 放宽为 `str | None`——**不在此处改契约**）。

## 安装

```bash
pip install ikc-open-platform-sdk          # PyPI（0.6.1，依赖 ikc-sdk-lib 0.18.0）
pip install sdk/python/                    # 或本地源码
```

## 快速开始

```python
from ikc_open_platform_sdk import OpenPlatformClient
from ikc_sdk.core.api.search.universal import SearchQueryRequest

with OpenPlatformClient("http://localhost:18000", api_key="<app-api-key>") as client:
    result = client.search.universal_search(SearchQueryRequest(query="IKC 平台"))
    for hit in result.hits:
        print(hit)
    client.wiki.stat("kb_10001")            # W-04
    client.graph.stat("kb_10001")           # G-01
    client.flash.policy()                   # M-10（记忆域加工策略快照）
```

## 检索 V2（`universal_search_v2`，D-03）

V2 把**文档 / Wiki / 图谱 / 事实**收进同一个召回面；V1（`universal_search`）行为不变、两版并存：

```python
from ikc_sdk.core.api.search.universal_v2 import UniversalSearchV2Request

resp = client.search.universal_search_v2(UniversalSearchV2Request(
    query="设备支持的最大并发数是多少？",
    kbIds=["kb_10001"],                    # 必填，1~20 个且不重复
    topK=10,
    include={"wikiPage": True, "graphEntities": True, "graphRelations": True},
))
resp.strategy        # 如 lexical@search-v2.1
resp.partial         # true = 某一路降级，原因见 warnings[]（如 vector_unavailable）
resp.nextCursor      # 不透明签名游标：原样回填 cursor，不得解析、不得跨查询复用
for hit in resp.hits:
    print(hit.retrievalId, hit.representationKind, hit.score, hit.snippet)
```

模型是 `extra="forbid"`：`tenantId` / `principalIds` / `authorizedOrgPaths` / `queryVector` / `index` / `routing`
等安全字段由平台按调用方身份注入，调用方不发送也不构造。`filters.currentVersionOnly` 缺省 `true`（只召回当前版本）。

## Wiki / 图谱（知识库子资源）

Wiki（W 域）与图谱（G 域）是知识库子资源，路径挂在 `/api/v1/knowledge-bases/{kbId}` 下，共用知识库读写门禁：

```python
from ikc_sdk.core.api.wiki.build import WikiBuildRequest

client.wiki.tree("kb_1", page=1, page_size=20)                 # W-01 页面树（根节点分页）
client.wiki.page("kb_1", stable_key="部署手册")                 # W-02 页面详情（stableKey / pageId 二选一）
client.wiki.export("kb_1", format="jsonl")                     # W-05 导出（只导出可见页）
client.wiki.build("kb_1", WikiBuildRequest(                    # W-06 同步：返回落地计数
    docId="doc_1", markdown="# 标题\n正文",
))
job = client.wiki.build("kb_1", {"docId": "doc_1", "markdown": "# 标题", "async": True})  # W-06 异步
job = client.wiki.job("kb_1", job.jobId)                       # W-07 轮询至 status 终态

# W-08~W-19 人工修正（写接口）：乐观锁 If-Match / 幂等 Idempotency-Key 可按关键字传入
client.wiki.page_patch("kb_1", "wiki_1", {"title": "新标题", "reason": "标题被截断"},
                       if_match="12")                                    # W-08 字段级 patch
client.wiki.page_retire("kb_1", "wiki_1", "同名重复页")                    # W-13 软删（retired）
client.wiki.corrections_apply("kb_1", {"corrections": [                    # W-16 修正包（dryRun 回 diff）
    {"op": "page.retire", "target": "wiki_2", "reason": "垃圾页"},
], "dryRun": True})
client.wiki.revisions("kb_1", page=1, page_size=20)                        # W-17 修订列表
client.wiki.revision_revert("kb_1", "wrev_1", "误操作回退")                 # W-18 回滚
client.wiki.submit_review("kb_1", "wiki_1", comment="请审核")               # W-19 提交发布审核
client.wiki.review_action("kb_1", "flow_1", "approve", comment="通过")      # W-19 审核动作

client.graph.nodes("kb_1", page=1, page_size=20, entity_type="ORG")   # G-02 实体
client.graph.edges("kb_1", relation_type="WORKS_AT")           # G-03 关系
client.graph.export("kb_1", format="json")                     # G-05 导出（北向只有 json / jsonl）
client.graph.search("kb_1", query="中国电信", top_k=3)          # G-04c 图内检索（先找实体 id）
client.graph.neighbors("kb_1", entity_id="ent_1", depth=1)     # G-04a 1 跳邻域
client.graph.paths("kb_1", source_entity_id="ent_1",           # G-04b 两实体最短路径
                   target_entity_id="ent_2", max_depth=3)
```

## 命令行（CLI）

安装后可用 `ikc-op`（或 `python -m ikc_open_platform_sdk.cli`）：

```bash
export OPEN_PLATFORM_BASE_URL=http://localhost:18000
export OPEN_PLATFORM_API_KEY=<app-api-key>

ikc-op kb-query --page 1 --page-size 20
ikc-op kb-get kb_10001
ikc-op search-query --query "IKC 平台" --kb-id kb_10001 --top-k 5
ikc-op search-v2 --query "IKC 平台" --kb-ids '["kb_10001"]' --top-k 10   # Search V2（D-03）
ikc-op wiki-stat --kb-id kb_10001
ikc-op wiki-build --kb-id kb_10001 --doc-id doc_1 --markdown-file ./doc.md --async
ikc-op wiki-page-patch --kb-id kb_10001 --page-id wiki_1 --payload '{"title":"新标题","reason":"标题被截断"}' --if-match 12
ikc-op wiki-page-retire --kb-id kb_10001 --page-id wiki_1 --reason '同名重复页'
ikc-op wiki-corrections-apply --kb-id kb_10001 --payload '{"corrections":[{"op":"page.retire","target":"wiki_2","reason":"垃圾页"}],"dryRun":true}'
ikc-op wiki-revisions --kb-id kb_10001 --page 1 --page-size 20
ikc-op wiki-review-action --kb-id kb_10001 --flow-id flow_1 --action approve --comment '通过'
ikc-op graph-nodes --kb-id kb_10001 --type ORG --page-size 50
ikc-op sys-catalog            # 免认证系统路由
```

退出码：0 成功；1 业务错误；2 未认证（100401）；3 无权限（100403）；5 占位未实现（501001）；6 传输层错误。

环境变量与全局选项：`OPEN_PLATFORM_BASE_URL` / `--base-url`、`OPEN_PLATFORM_API_KEY` / `--api-key`、
`--timeout`、`OPEN_PLATFORM_EXTRA_HEADERS` / `--extra-headers`（JSON 对象）。平台 `AUTH_MODE=static` /
`gateway_header` 时业务接口要求身份头，靠 `--extra-headers` 发
`{"X-User-Id":"u_1","X-Tenant-Id":"t_1"}`（经平台自带 HAProxy 时同发 `X-Auth-User-Id` / `X-Auth-Tenant-Id`），
实例路由头 `X-Ikc-Instance-Id` 也走这里；缺身份头会回 `100401`。

## MCP Server（stdio）

安装后可用 `ikc-op-mcp`（或 `python -m ikc_open_platform_sdk.mcp --transport stdio`），向 MCP 客户端暴露 55 个工具（kb_* / doc_* / parse_* / search_* / wiki_*【含 W-08~W-19 写面】/ graph_* / flash_* / sys_*），仅需 Python 标准库（NDJSON JSON-RPC 2.0）。

## 测试

```bash
python -m pytest sdk/python/tests -q
```
