ocai-deepseek 0.1.1__tar.gz
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.
- ocai_deepseek-0.1.1/.gitignore +60 -0
- ocai_deepseek-0.1.1/CHANGELOG.md +24 -0
- ocai_deepseek-0.1.1/PKG-INFO +46 -0
- ocai_deepseek-0.1.1/README.md +31 -0
- ocai_deepseek-0.1.1/pyproject.toml +28 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/__init__.py +5 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/__init__.py +14 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/codec.py +168 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/descriptor.py +43 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/edges.py +221 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/evidence.py +115 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/policy.py +240 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/usage.py +110 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/chat_completions/wire.py +11 -0
- ocai_deepseek-0.1.1/src/ocai/deepseek/py.typed +0 -0
- ocai_deepseek-0.1.1/tests/test_conformance.py +120 -0
- ocai_deepseek-0.1.1/tests/test_descriptor.py +92 -0
- ocai_deepseek-0.1.1/tests/test_semantics.py +194 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
*.so
|
|
9
|
+
|
|
10
|
+
# uv / venv
|
|
11
|
+
.venv/
|
|
12
|
+
uv.lock.bak
|
|
13
|
+
|
|
14
|
+
# Tooling caches
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.import_linter_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# Docs site build output and page cache (zensical build)
|
|
23
|
+
/site/
|
|
24
|
+
/.cache/
|
|
25
|
+
|
|
26
|
+
# Node (future typescript/)
|
|
27
|
+
node_modules/
|
|
28
|
+
*.tsbuildinfo
|
|
29
|
+
|
|
30
|
+
# Go (future go/)
|
|
31
|
+
/go/bin/
|
|
32
|
+
|
|
33
|
+
# Editors / OS. Shared editor settings ARE committed: the multi-root workspace
|
|
34
|
+
# (ocai.code-workspace) and each folder's .vscode/settings.json + extensions.json
|
|
35
|
+
# give Pylance/Ruff the right interpreter per project. Personal files stay local.
|
|
36
|
+
.idea/
|
|
37
|
+
.vscode/*
|
|
38
|
+
!.vscode/settings.json
|
|
39
|
+
!.vscode/extensions.json
|
|
40
|
+
.DS_Store
|
|
41
|
+
|
|
42
|
+
# Per-user agent settings (never commit personal permissions)
|
|
43
|
+
.claude/settings.local.json
|
|
44
|
+
.codex/config.toml
|
|
45
|
+
|
|
46
|
+
# Platform build and browser-test artifacts
|
|
47
|
+
.nuxt/
|
|
48
|
+
.output/
|
|
49
|
+
platform/test-results/
|
|
50
|
+
platform/playwright-report/
|
|
51
|
+
|
|
52
|
+
# Local environment files: the root .env is the active one, .envs/ holds the
|
|
53
|
+
# per-environment variants (`task env -- <ENV>` copies .envs/.env.<ENV> to .env).
|
|
54
|
+
# Never committed: they hold credentials.
|
|
55
|
+
/.env
|
|
56
|
+
/.envs/
|
|
57
|
+
.local/
|
|
58
|
+
|
|
59
|
+
# Task execution fingerprints
|
|
60
|
+
.task/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog — ocai-deepseek
|
|
2
|
+
|
|
3
|
+
All notable changes to the `ocai-deepseek` distribution. Generated from the change files in
|
|
4
|
+
`.changeset/` by the release workflow (ADR 0010); do not edit released sections by hand.
|
|
5
|
+
## 0.1.1 (2026-11-11)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
#### Declare the independently attributable DeepSeek interface package
|
|
10
|
+
|
|
11
|
+
Declare the independently attributable DeepSeek interface package. (WU-44a, #89)
|
|
12
|
+
|
|
13
|
+
#### Qualify independent DeepSeek unary conversion
|
|
14
|
+
|
|
15
|
+
Share compatible mapping through explicit variant configuration while preserving
|
|
16
|
+
DeepSeek identity, mandatory reasoning replay, honest parameter effects and
|
|
17
|
+
measured usage. Add independently censused request encode/audit and response
|
|
18
|
+
decode edges with recoverable unknown-field evidence. (WU-44b, #91)
|
|
19
|
+
|
|
20
|
+
### Fixes
|
|
21
|
+
|
|
22
|
+
#### Package metadata points at the real repository and the DeepSeek plugin has an extra
|
|
23
|
+
|
|
24
|
+
Homepage, Source, Documentation and Changelog URLs now point at `github.com/ocarinow/ocai` and the docs site. `ocai[deepseek]` installs the DeepSeek plugin and `ocai[all]` includes it. No runtime behavior changed.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ocai-deepseek
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: DeepSeek interface descriptors for ocai; execution qualification pending.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ocarinow/ocai
|
|
6
|
+
Project-URL: Source, https://github.com/ocarinow/ocai
|
|
7
|
+
Project-URL: Documentation, https://ocarinow.github.io/ocai/
|
|
8
|
+
Project-URL: Changelog, https://github.com/ocarinow/ocai/blob/main/python/packages/ocai-deepseek/CHANGELOG.md
|
|
9
|
+
Author: ocai maintainers
|
|
10
|
+
License-Expression: FSL-1.1-ALv2
|
|
11
|
+
Requires-Python: >=3.13
|
|
12
|
+
Requires-Dist: ocai-openai<0.2,>=0.1
|
|
13
|
+
Requires-Dist: ocai<0.2,>=0.1
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# ocai-deepseek
|
|
17
|
+
|
|
18
|
+
DeepSeek's separately attributable Chat Completions interface for ocai.
|
|
19
|
+
This source-available package uses FSL-1.1-ALv2.
|
|
20
|
+
|
|
21
|
+
The catalog publishes independently censused unary request encode, request audit
|
|
22
|
+
and response decode edges. Text, function tools, JSON-object output, reasoning
|
|
23
|
+
replay, native finish state and measured usage are qualified by golden fixtures.
|
|
24
|
+
Unknown native data remains recoverable in registered extension banks.
|
|
25
|
+
|
|
26
|
+
There is no registered serving component or streaming edge yet: public chat
|
|
27
|
+
execution fails before provider I/O. Compatible mapping code and wire DTOs reuse
|
|
28
|
+
ocai-openai, while DeepSeek retains its own identity, profiles and contracts.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from ocai.convert import Catalog
|
|
32
|
+
from ocai.deepseek import FRAGMENT
|
|
33
|
+
|
|
34
|
+
catalog = Catalog.of(FRAGMENT)
|
|
35
|
+
lock = catalog.lock()
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`deepseek/chat_completions@2026-11` names ocai's documented-wire observation
|
|
39
|
+
snapshot dated 2026-11-11. It is neither a vendor version header nor a model
|
|
40
|
+
release. Model facts and exclusions are recorded in `docs/providers/deepseek.md`.
|
|
41
|
+
WU-45 enables public unary execution; WU-46 qualifies streaming.
|
|
42
|
+
|
|
43
|
+
Tool histories require original reasoning text for every assistant turn. Missing
|
|
44
|
+
reasoning and unqualified model-dependent top_p are reported UNSUPPORTED. Media,
|
|
45
|
+
beta strict tools, FIM, prefix completion, JSON-schema output, Responses and
|
|
46
|
+
Anthropic-compatible endpoints are outside this initial surface.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# ocai-deepseek
|
|
2
|
+
|
|
3
|
+
DeepSeek's separately attributable Chat Completions interface for ocai.
|
|
4
|
+
This source-available package uses FSL-1.1-ALv2.
|
|
5
|
+
|
|
6
|
+
The catalog publishes independently censused unary request encode, request audit
|
|
7
|
+
and response decode edges. Text, function tools, JSON-object output, reasoning
|
|
8
|
+
replay, native finish state and measured usage are qualified by golden fixtures.
|
|
9
|
+
Unknown native data remains recoverable in registered extension banks.
|
|
10
|
+
|
|
11
|
+
There is no registered serving component or streaming edge yet: public chat
|
|
12
|
+
execution fails before provider I/O. Compatible mapping code and wire DTOs reuse
|
|
13
|
+
ocai-openai, while DeepSeek retains its own identity, profiles and contracts.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from ocai.convert import Catalog
|
|
17
|
+
from ocai.deepseek import FRAGMENT
|
|
18
|
+
|
|
19
|
+
catalog = Catalog.of(FRAGMENT)
|
|
20
|
+
lock = catalog.lock()
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`deepseek/chat_completions@2026-11` names ocai's documented-wire observation
|
|
24
|
+
snapshot dated 2026-11-11. It is neither a vendor version header nor a model
|
|
25
|
+
release. Model facts and exclusions are recorded in `docs/providers/deepseek.md`.
|
|
26
|
+
WU-45 enables public unary execution; WU-46 qualifies streaming.
|
|
27
|
+
|
|
28
|
+
Tool histories require original reasoning text for every assistant turn. Missing
|
|
29
|
+
reasoning and unqualified model-dependent top_p are reported UNSUPPORTED. Media,
|
|
30
|
+
beta strict tools, FIM, prefix completion, JSON-schema output, Responses and
|
|
31
|
+
Anthropic-compatible endpoints are outside this initial surface.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ocai-deepseek"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "DeepSeek interface descriptors for ocai; execution qualification pending."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.13"
|
|
11
|
+
license = "FSL-1.1-ALv2"
|
|
12
|
+
authors = [{ name = "ocai maintainers" }]
|
|
13
|
+
dependencies = ["ocai>=0.1,<0.2", "ocai-openai>=0.1,<0.2"]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://github.com/ocarinow/ocai"
|
|
17
|
+
Source = "https://github.com/ocarinow/ocai"
|
|
18
|
+
Documentation = "https://ocarinow.github.io/ocai/"
|
|
19
|
+
Changelog = "https://github.com/ocarinow/ocai/blob/main/python/packages/ocai-deepseek/CHANGELOG.md"
|
|
20
|
+
|
|
21
|
+
[project.entry-points."ocai.fragments"]
|
|
22
|
+
deepseek = "ocai.deepseek:FRAGMENT"
|
|
23
|
+
|
|
24
|
+
[tool.hatch.build.targets.wheel]
|
|
25
|
+
packages = ["src/ocai"]
|
|
26
|
+
|
|
27
|
+
[tool.hatch.build]
|
|
28
|
+
dev-mode-dirs = ["src"]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Independently qualified unary DeepSeek Chat Completions interface; no serveable component yet."""
|
|
2
|
+
|
|
3
|
+
from ocai.convert.catalog import CatalogFragment
|
|
4
|
+
from ocai.deepseek.chat_completions.descriptor import NODES
|
|
5
|
+
from ocai.deepseek.chat_completions.descriptor import ORIGIN
|
|
6
|
+
from ocai.deepseek.chat_completions.descriptor import PROFILES
|
|
7
|
+
from ocai.deepseek.chat_completions.descriptor import TRAITS
|
|
8
|
+
from ocai.deepseek.chat_completions.edges import EDGES
|
|
9
|
+
|
|
10
|
+
__all__ = ["FRAGMENT"]
|
|
11
|
+
|
|
12
|
+
FRAGMENT = CatalogFragment(
|
|
13
|
+
origin=ORIGIN, nodes=NODES, profiles=PROFILES, traits=(TRAITS,), edges=EDGES
|
|
14
|
+
)
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""DeepSeek unary semantics over the shared, explicitly configured compatible codec."""
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from dataclasses import replace
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ocai.chat.types import ChatRequest
|
|
8
|
+
from ocai.chat.types import Part
|
|
9
|
+
from ocai.chat.types import PartText
|
|
10
|
+
from ocai.chat.types import PartUnknown
|
|
11
|
+
from ocai.convert.graph import EdgeOutput
|
|
12
|
+
from ocai.core.fidelity import Disposition
|
|
13
|
+
from ocai.core.fidelity import FieldLoss
|
|
14
|
+
from ocai.core.ir import is_json_array
|
|
15
|
+
from ocai.core.ir import is_json_object
|
|
16
|
+
from ocai.deepseek.chat_completions import descriptor
|
|
17
|
+
from ocai.deepseek.chat_completions.evidence import Evidence
|
|
18
|
+
from ocai.deepseek.chat_completions.evidence import fields
|
|
19
|
+
from ocai.deepseek.chat_completions.evidence import response_payload
|
|
20
|
+
from ocai.deepseek.chat_completions.evidence import retain
|
|
21
|
+
from ocai.deepseek.chat_completions.evidence import tool_calls
|
|
22
|
+
from ocai.deepseek.chat_completions.policy import NAMESPACE
|
|
23
|
+
from ocai.deepseek.chat_completions.policy import inspect_request
|
|
24
|
+
from ocai.deepseek.chat_completions.usage import decode_usage
|
|
25
|
+
from ocai.openai.chat_completions.codec import ChatCompletionsCodec
|
|
26
|
+
from ocai.openai.chat_completions.variant import ChatCompletionsVariant
|
|
27
|
+
|
|
28
|
+
VARIANT = ChatCompletionsVariant(
|
|
29
|
+
request_node=descriptor.CHAT_COMPLETIONS_REQUEST,
|
|
30
|
+
response_node=descriptor.CHAT_COMPLETIONS_RESPONSE,
|
|
31
|
+
chunk_node=descriptor.CHAT_COMPLETIONS_CHUNK,
|
|
32
|
+
traits=descriptor.TRAITS,
|
|
33
|
+
path=descriptor.PATH,
|
|
34
|
+
reasoning_field="reasoning_content",
|
|
35
|
+
max_tokens_field="max_tokens",
|
|
36
|
+
knob_ranges=(("temperature", 0.0, 2.0),),
|
|
37
|
+
finish_reasons=(("insufficient_system_resource", "error"), ("aborted", "error")),
|
|
38
|
+
)
|
|
39
|
+
_REQUEST_FIELDS = {
|
|
40
|
+
"model",
|
|
41
|
+
"messages",
|
|
42
|
+
"tools",
|
|
43
|
+
"tool_choice",
|
|
44
|
+
"temperature",
|
|
45
|
+
"top_p",
|
|
46
|
+
"seed",
|
|
47
|
+
"frequency_penalty",
|
|
48
|
+
"presence_penalty",
|
|
49
|
+
"parallel_tool_calls",
|
|
50
|
+
"logprobs",
|
|
51
|
+
"max_completion_tokens",
|
|
52
|
+
"max_tokens",
|
|
53
|
+
"stop",
|
|
54
|
+
"reasoning_effort",
|
|
55
|
+
"response_format",
|
|
56
|
+
"thinking",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _bank(extensions: dict[str, Any], evidence: Evidence, key: str) -> dict[str, Any]:
|
|
61
|
+
"""Collect native extension values without minting unregistered tomorrow-keys."""
|
|
62
|
+
for name, value in extensions.items():
|
|
63
|
+
retain(evidence, name.removeprefix("deepseek."), value)
|
|
64
|
+
evidence.sort(key=lambda record: record["path"])
|
|
65
|
+
return {key: evidence} if evidence else {}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _notes(losses: list[FieldLoss]) -> tuple[FieldLoss, ...]:
|
|
69
|
+
return tuple(replace(loss, note=loss.note.replace("openai.", "deepseek.")) for loss in losses)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class DeepSeekCodec(ChatCompletionsCodec):
|
|
73
|
+
"""Qualify text, tools, JSON-object and reasoning without enabling execution yet."""
|
|
74
|
+
|
|
75
|
+
def __init__(self) -> None:
|
|
76
|
+
"""Use DeepSeek coordinates and field lanes, never OpenAI routing identity."""
|
|
77
|
+
super().__init__(VARIANT)
|
|
78
|
+
|
|
79
|
+
def encode_request(self, request: ChatRequest) -> EdgeOutput:
|
|
80
|
+
"""Apply semantic findings to the effective shared-codec output before provider I/O."""
|
|
81
|
+
out = super().encode_request(request)
|
|
82
|
+
losses, shifts = list(out.losses), list(out.shifts)
|
|
83
|
+
inspect_request(request, out.value, losses, shifts)
|
|
84
|
+
return EdgeOutput(out.value, _notes(losses), tuple(shifts))
|
|
85
|
+
|
|
86
|
+
def decode_request(self, payload: dict[str, Any]) -> EdgeOutput:
|
|
87
|
+
"""Decode compatible request data and retain unknown native fields by source path."""
|
|
88
|
+
evidence: Evidence = []
|
|
89
|
+
raw: Any = payload
|
|
90
|
+
if not is_json_object(raw):
|
|
91
|
+
retain(evidence, "$", raw)
|
|
92
|
+
raw = {}
|
|
93
|
+
safe = fields(raw, _REQUEST_FIELDS, "", evidence)
|
|
94
|
+
thinking = safe.pop("thinking", None)
|
|
95
|
+
messages = safe.get("messages")
|
|
96
|
+
if is_json_array(messages):
|
|
97
|
+
for index, message in enumerate(messages):
|
|
98
|
+
if not is_json_object(message):
|
|
99
|
+
continue # shared tolerant reader retains the malformed entry
|
|
100
|
+
role = message.get("role")
|
|
101
|
+
if not isinstance(role, str):
|
|
102
|
+
retain(evidence, f"messages[{index}].role", role)
|
|
103
|
+
message["role"] = "unknown"
|
|
104
|
+
if "tool_calls" in message:
|
|
105
|
+
message["tool_calls"] = tool_calls(
|
|
106
|
+
message["tool_calls"], f"messages[{index}].tool_calls", evidence
|
|
107
|
+
)
|
|
108
|
+
out = super().decode_request(safe)
|
|
109
|
+
request = out.value
|
|
110
|
+
additional_evidence = bool(evidence)
|
|
111
|
+
request.extensions = _bank(request.extensions, evidence, "deepseek.request_unmapped")
|
|
112
|
+
if "thinking" in raw:
|
|
113
|
+
request.provider_options[NAMESPACE] = {"thinking": deepcopy(thinking)}
|
|
114
|
+
losses = list(out.losses)
|
|
115
|
+
if additional_evidence and not any(loss.path == "unmapped" for loss in losses):
|
|
116
|
+
losses.append(
|
|
117
|
+
FieldLoss(
|
|
118
|
+
"unmapped",
|
|
119
|
+
Disposition.EXTENSIONS,
|
|
120
|
+
note="unknown native request data retained by source path",
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
return EdgeOutput(request, _notes(losses), out.shifts)
|
|
124
|
+
|
|
125
|
+
def _decode_request_content(
|
|
126
|
+
self, index: int, wire_msg: dict[str, Any], losses: list[FieldLoss]
|
|
127
|
+
) -> list[Part]:
|
|
128
|
+
"""Keep future native content tags as unknown parts, without inventing media support."""
|
|
129
|
+
content = wire_msg.get("content")
|
|
130
|
+
if not is_json_array(content):
|
|
131
|
+
return super()._decode_request_content(index, wire_msg, losses)
|
|
132
|
+
parts: list[Part] = []
|
|
133
|
+
for position, item in enumerate(content):
|
|
134
|
+
if not is_json_object(item):
|
|
135
|
+
continue # the shared request evidence sweep retains malformed scalar entries
|
|
136
|
+
if item.get("type") == "text" and isinstance(item.get("text"), str):
|
|
137
|
+
parts.append(PartText(text=item["text"]))
|
|
138
|
+
else:
|
|
139
|
+
parts.append(PartUnknown.from_dict(deepcopy(item)))
|
|
140
|
+
losses.append(
|
|
141
|
+
FieldLoss(
|
|
142
|
+
f"messages[{index}].content[{position}]",
|
|
143
|
+
Disposition.EXTENSIONS,
|
|
144
|
+
note="unqualified native content preserved as PartUnknown",
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
return parts
|
|
148
|
+
|
|
149
|
+
def decode_response(self, payload: dict[str, Any]) -> EdgeOutput:
|
|
150
|
+
"""Preserve reasoning, native identity and disjoint measured usage through total decode."""
|
|
151
|
+
safe, evidence = response_payload(payload)
|
|
152
|
+
native_usage = safe.pop("usage", None)
|
|
153
|
+
out = super().decode_response(safe)
|
|
154
|
+
response = out.value
|
|
155
|
+
losses = list(out.losses)
|
|
156
|
+
response.usage = decode_usage(native_usage, losses)
|
|
157
|
+
response.raw = deepcopy(payload)
|
|
158
|
+
additional_evidence = bool(evidence)
|
|
159
|
+
response.extensions = _bank(response.extensions, evidence, "deepseek.response_unmapped")
|
|
160
|
+
if additional_evidence:
|
|
161
|
+
losses.append(
|
|
162
|
+
FieldLoss(
|
|
163
|
+
"unmapped",
|
|
164
|
+
Disposition.EXTENSIONS,
|
|
165
|
+
note="unknown native response data retained by source path",
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
return EdgeOutput(response, _notes(losses), out.shifts)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""DeepSeek identity and hosting facts, distinct from conversion qualification."""
|
|
2
|
+
|
|
3
|
+
from datetime import date
|
|
4
|
+
|
|
5
|
+
from ocai.core.identity import CHAT_CHUNK
|
|
6
|
+
from ocai.core.identity import CHAT_REQUEST
|
|
7
|
+
from ocai.core.identity import CHAT_RESPONSE
|
|
8
|
+
from ocai.core.identity import NodeId
|
|
9
|
+
from ocai.core.identity import Origin
|
|
10
|
+
from ocai.core.identity import Status
|
|
11
|
+
from ocai.core.profile import CapabilityProfile
|
|
12
|
+
from ocai.core.profile import Support
|
|
13
|
+
from ocai.core.traits import DialectTraits
|
|
14
|
+
|
|
15
|
+
PROVIDER = "deepseek"
|
|
16
|
+
INTERFACE = "chat_completions"
|
|
17
|
+
# Observation snapshot, not a vendor API version or model release.
|
|
18
|
+
TAG = "2026-11"
|
|
19
|
+
RELEASED = date(2026, 11, 11)
|
|
20
|
+
BASE_URL = "https://api.deepseek.com"
|
|
21
|
+
PATH = "/chat/completions"
|
|
22
|
+
MODEL_IDS = ("deepseek-flash", "deepseek-v4-pro")
|
|
23
|
+
ORIGIN = Origin(distribution="ocai-deepseek", version="0.1.0")
|
|
24
|
+
|
|
25
|
+
CHAT_COMPLETIONS_REQUEST = NodeId(PROVIDER, INTERFACE, TAG, CHAT_REQUEST, RELEASED, Status.STABLE)
|
|
26
|
+
CHAT_COMPLETIONS_RESPONSE = NodeId(PROVIDER, INTERFACE, TAG, CHAT_RESPONSE, RELEASED, Status.STABLE)
|
|
27
|
+
CHAT_COMPLETIONS_CHUNK = NodeId(PROVIDER, INTERFACE, TAG, CHAT_CHUNK, RELEASED, Status.STABLE)
|
|
28
|
+
NODES = (CHAT_COMPLETIONS_REQUEST, CHAT_COMPLETIONS_RESPONSE, CHAT_COMPLETIONS_CHUNK)
|
|
29
|
+
TRAITS = DialectTraits(vendor=PROVIDER, first_party_base_url=BASE_URL)
|
|
30
|
+
# Only independently qualified features are declared; media remains unknown.
|
|
31
|
+
PROFILES = tuple(
|
|
32
|
+
CapabilityProfile(
|
|
33
|
+
provider=PROVIDER,
|
|
34
|
+
interface=INTERFACE,
|
|
35
|
+
model_pattern=model,
|
|
36
|
+
features={
|
|
37
|
+
"chat.config.output.json_schema": Support.ABSENT,
|
|
38
|
+
"chat.config.output.json": Support.NATIVE,
|
|
39
|
+
"chat.parts.reasoning.replay": Support.NATIVE,
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
for model in MODEL_IDS
|
|
43
|
+
)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Independently censused DeepSeek unary edges; no serving or stream registration."""
|
|
2
|
+
|
|
3
|
+
from ocai.convert.contract import DeclaredDisposition
|
|
4
|
+
from ocai.convert.contract import EdgeContract
|
|
5
|
+
from ocai.convert.graph import Edge
|
|
6
|
+
from ocai.core.fidelity import Disposition
|
|
7
|
+
from ocai.core.fidelity import SemanticShift
|
|
8
|
+
from ocai.core.identity import CHAT_REQUEST
|
|
9
|
+
from ocai.core.identity import CHAT_RESPONSE
|
|
10
|
+
from ocai.core.identity import canonical_node
|
|
11
|
+
from ocai.deepseek.chat_completions.codec import DeepSeekCodec
|
|
12
|
+
from ocai.deepseek.chat_completions.descriptor import CHAT_COMPLETIONS_REQUEST
|
|
13
|
+
from ocai.deepseek.chat_completions.descriptor import CHAT_COMPLETIONS_RESPONSE
|
|
14
|
+
from ocai.deepseek.chat_completions.descriptor import ORIGIN
|
|
15
|
+
|
|
16
|
+
_CODEC = DeepSeekCodec()
|
|
17
|
+
|
|
18
|
+
ENCODE_REQUEST_CONTRACT = EdgeContract(
|
|
19
|
+
census={
|
|
20
|
+
**{
|
|
21
|
+
f"{path}.{lane}": DeclaredDisposition(Disposition.UNSUPPORTED)
|
|
22
|
+
for path in (
|
|
23
|
+
"config",
|
|
24
|
+
"config.reasoning",
|
|
25
|
+
"config.output",
|
|
26
|
+
"config.audio",
|
|
27
|
+
"config.cache",
|
|
28
|
+
"messages[]",
|
|
29
|
+
"messages[].parts[]",
|
|
30
|
+
"messages[].parts[].parts[]",
|
|
31
|
+
"messages[].parts[].annotations[]",
|
|
32
|
+
"tools[]",
|
|
33
|
+
"tool_choice",
|
|
34
|
+
)
|
|
35
|
+
for lane in ("extensions[]", "provider_options[deepseek.chat_completions]")
|
|
36
|
+
},
|
|
37
|
+
"messages[].role": DeclaredDisposition(Disposition.EXACT),
|
|
38
|
+
"messages[].parts[text]": DeclaredDisposition(Disposition.EXACT),
|
|
39
|
+
"messages[].parts[tool_call]": DeclaredDisposition(Disposition.EXACT),
|
|
40
|
+
"messages[].parts[reasoning]": DeclaredDisposition(
|
|
41
|
+
Disposition.UNSUPPORTED,
|
|
42
|
+
"required history must be present; plain text replay otherwise maps exactly",
|
|
43
|
+
),
|
|
44
|
+
"messages[].parts[]": DeclaredDisposition(
|
|
45
|
+
Disposition.DROPPED, "media, server tools and unqualified parts have no mapped lane"
|
|
46
|
+
),
|
|
47
|
+
"config.stop_sequences": DeclaredDisposition(Disposition.RENAMED),
|
|
48
|
+
"messages[].parts[].text": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
49
|
+
"messages[].parts[].annotations": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
50
|
+
"messages[].parts[].anchor": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
51
|
+
"messages[].parts[].signature": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
52
|
+
"messages[].parts[].opaque": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
53
|
+
"messages[].parts[].source": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
54
|
+
"messages[].parts[].annotations[].opaque": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
55
|
+
"messages[].parts[].is_error": DeclaredDisposition(Disposition.DROPPED),
|
|
56
|
+
"messages[].parts[].parts[]": DeclaredDisposition(Disposition.DROPPED),
|
|
57
|
+
"messages": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
58
|
+
"tools": DeclaredDisposition(Disposition.EXACT),
|
|
59
|
+
"tools[]": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
60
|
+
"tool_choice": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
61
|
+
"anchors[]": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
62
|
+
"extensions[]": DeclaredDisposition(Disposition.DROPPED),
|
|
63
|
+
"extensions[ocai.request_unparsed_anchors]": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
64
|
+
"config.temperature": DeclaredDisposition(Disposition.APPROXIMATED),
|
|
65
|
+
"config.top_p": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
66
|
+
"config.seed": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
67
|
+
"config.frequency_penalty": DeclaredDisposition(Disposition.EXACT),
|
|
68
|
+
"config.presence_penalty": DeclaredDisposition(Disposition.EXACT),
|
|
69
|
+
"config.parallel_tool_calls": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
70
|
+
"config.max_output_tokens": DeclaredDisposition(Disposition.APPROXIMATED),
|
|
71
|
+
"config.reasoning.budget_tokens": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
72
|
+
"config.reasoning.include_thoughts": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
73
|
+
"messages[].parts[refusal]": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
74
|
+
"provider_options[deepseek.chat_completions].tools": DeclaredDisposition(
|
|
75
|
+
Disposition.UNSUPPORTED
|
|
76
|
+
),
|
|
77
|
+
"config.reasoning.effort": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
78
|
+
"config.output": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
79
|
+
"config.top_k": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
80
|
+
"config.logprobs": DeclaredDisposition(Disposition.EXACT),
|
|
81
|
+
"config.modalities": DeclaredDisposition(Disposition.DROPPED),
|
|
82
|
+
"config.audio": DeclaredDisposition(Disposition.DROPPED),
|
|
83
|
+
"config.cache": DeclaredDisposition(Disposition.DROPPED),
|
|
84
|
+
**{
|
|
85
|
+
f"provider_options[deepseek.chat_completions].{key}": DeclaredDisposition(
|
|
86
|
+
Disposition.UNSUPPORTED
|
|
87
|
+
)
|
|
88
|
+
for key in (
|
|
89
|
+
"thinking",
|
|
90
|
+
"reasoning_effort",
|
|
91
|
+
"top_p",
|
|
92
|
+
"seed",
|
|
93
|
+
"parallel_tool_calls",
|
|
94
|
+
"max_completion_tokens",
|
|
95
|
+
"n",
|
|
96
|
+
"tool_choice",
|
|
97
|
+
"response_format",
|
|
98
|
+
)
|
|
99
|
+
},
|
|
100
|
+
"provider_options[deepseek.chat_completions].max_tokens": DeclaredDisposition(
|
|
101
|
+
Disposition.APPROXIMATED
|
|
102
|
+
),
|
|
103
|
+
(
|
|
104
|
+
"provider_options[deepseek.chat_completions].messages[].reasoning_content"
|
|
105
|
+
): DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
106
|
+
},
|
|
107
|
+
semantic_shifts=(
|
|
108
|
+
*(
|
|
109
|
+
SemanticShift(
|
|
110
|
+
kind="deepseek.thinking_override",
|
|
111
|
+
path=path,
|
|
112
|
+
note="thinking selector overrides effort",
|
|
113
|
+
)
|
|
114
|
+
for path in (
|
|
115
|
+
"config.reasoning.effort",
|
|
116
|
+
"provider_options[deepseek.chat_completions].reasoning_effort",
|
|
117
|
+
)
|
|
118
|
+
),
|
|
119
|
+
SemanticShift(
|
|
120
|
+
kind="relocation",
|
|
121
|
+
path="messages[].parts[]",
|
|
122
|
+
note="tool results relocate into sibling tool messages",
|
|
123
|
+
),
|
|
124
|
+
*(
|
|
125
|
+
SemanticShift(
|
|
126
|
+
kind="deepseek.ignored_parameter",
|
|
127
|
+
path=path,
|
|
128
|
+
note="provider accepts but ignores the supplied parameter",
|
|
129
|
+
)
|
|
130
|
+
for key in ("temperature", "frequency_penalty", "presence_penalty")
|
|
131
|
+
for path in (f"config.{key}", f"provider_options[deepseek.chat_completions].{key}")
|
|
132
|
+
),
|
|
133
|
+
*(
|
|
134
|
+
SemanticShift(
|
|
135
|
+
kind="deepseek.effort_alias",
|
|
136
|
+
path=path,
|
|
137
|
+
note="provider interprets an effort alias; supplied value stays verbatim",
|
|
138
|
+
)
|
|
139
|
+
for path in (
|
|
140
|
+
"config.reasoning.effort",
|
|
141
|
+
"provider_options[deepseek.chat_completions].reasoning_effort",
|
|
142
|
+
)
|
|
143
|
+
),
|
|
144
|
+
SemanticShift(
|
|
145
|
+
kind="deepseek.reasoning_ignored",
|
|
146
|
+
path="messages[].parts[reasoning]",
|
|
147
|
+
note="provider ignores reasoning replay without tools",
|
|
148
|
+
),
|
|
149
|
+
SemanticShift(
|
|
150
|
+
kind="deepseek.reasoning_ignored",
|
|
151
|
+
path="provider_options[deepseek.chat_completions].messages[].reasoning_content",
|
|
152
|
+
note="provider ignores reasoning replay without tools",
|
|
153
|
+
),
|
|
154
|
+
SemanticShift(
|
|
155
|
+
kind="deepseek.reasoning_concatenated",
|
|
156
|
+
path="messages[].parts[reasoning]",
|
|
157
|
+
note="multiple reasoning parts concatenate into the native text lane",
|
|
158
|
+
),
|
|
159
|
+
),
|
|
160
|
+
note="canonical request to independently qualified DeepSeek compatible wire",
|
|
161
|
+
)
|
|
162
|
+
DECODE_REQUEST_CONTRACT = EdgeContract(
|
|
163
|
+
census={
|
|
164
|
+
"model": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
165
|
+
"unmapped": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
166
|
+
"tools[]": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
167
|
+
"tool_choice": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
168
|
+
"response_format": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
169
|
+
"messages[].content[]": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
170
|
+
"n": DeclaredDisposition(Disposition.UNSUPPORTED),
|
|
171
|
+
},
|
|
172
|
+
semantic_shifts=(
|
|
173
|
+
SemanticShift(
|
|
174
|
+
kind="relocation",
|
|
175
|
+
path="messages[]",
|
|
176
|
+
note="native tool message rethreads into a canonical tool turn",
|
|
177
|
+
),
|
|
178
|
+
),
|
|
179
|
+
note="DeepSeek request audit with exact native reasoning and unknown evidence",
|
|
180
|
+
)
|
|
181
|
+
DECODE_RESPONSE_CONTRACT = EdgeContract(
|
|
182
|
+
census={
|
|
183
|
+
"choices[0].message.content": DeclaredDisposition(Disposition.EXACT),
|
|
184
|
+
"choices[0].message.reasoning_content": DeclaredDisposition(Disposition.EXACT),
|
|
185
|
+
"choices[0].message.tool_calls[]": DeclaredDisposition(Disposition.EXACT),
|
|
186
|
+
"choices[0].finish_reason": DeclaredDisposition(Disposition.EXACT),
|
|
187
|
+
"choices[0].logprobs": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
188
|
+
"unmapped": DeclaredDisposition(Disposition.EXTENSIONS),
|
|
189
|
+
"usage": DeclaredDisposition(
|
|
190
|
+
Disposition.EXTENSIONS,
|
|
191
|
+
"known disjoint counters map exactly; uncertain measurements remain evidence",
|
|
192
|
+
),
|
|
193
|
+
"id": DeclaredDisposition(Disposition.EXACT),
|
|
194
|
+
"model": DeclaredDisposition(Disposition.EXACT),
|
|
195
|
+
"created": DeclaredDisposition(Disposition.RENAMED),
|
|
196
|
+
},
|
|
197
|
+
note="DeepSeek response to canonical text, reasoning, tools and measured usage",
|
|
198
|
+
)
|
|
199
|
+
EDGES = (
|
|
200
|
+
Edge(
|
|
201
|
+
canonical_node(CHAT_REQUEST),
|
|
202
|
+
CHAT_COMPLETIONS_REQUEST,
|
|
203
|
+
_CODEC.encode_request,
|
|
204
|
+
ENCODE_REQUEST_CONTRACT,
|
|
205
|
+
ORIGIN,
|
|
206
|
+
),
|
|
207
|
+
Edge(
|
|
208
|
+
CHAT_COMPLETIONS_REQUEST,
|
|
209
|
+
canonical_node(CHAT_REQUEST),
|
|
210
|
+
_CODEC.decode_request,
|
|
211
|
+
DECODE_REQUEST_CONTRACT,
|
|
212
|
+
ORIGIN,
|
|
213
|
+
),
|
|
214
|
+
Edge(
|
|
215
|
+
CHAT_COMPLETIONS_RESPONSE,
|
|
216
|
+
canonical_node(CHAT_RESPONSE),
|
|
217
|
+
_CODEC.decode_response,
|
|
218
|
+
DECODE_RESPONSE_CONTRACT,
|
|
219
|
+
ORIGIN,
|
|
220
|
+
),
|
|
221
|
+
)
|