draft-protocol 0.1.0__py3-none-any.whl
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.
- draft_protocol/__init__.py +65 -0
- draft_protocol/__main__.py +61 -0
- draft_protocol/config.py +112 -0
- draft_protocol/engine.py +724 -0
- draft_protocol/providers.py +222 -0
- draft_protocol/py.typed +0 -0
- draft_protocol/rest.py +168 -0
- draft_protocol/server.py +367 -0
- draft_protocol/storage.py +130 -0
- draft_protocol-0.1.0.dist-info/METADATA +362 -0
- draft_protocol-0.1.0.dist-info/RECORD +14 -0
- draft_protocol-0.1.0.dist-info/WHEEL +4 -0
- draft_protocol-0.1.0.dist-info/entry_points.txt +2 -0
- draft_protocol-0.1.0.dist-info/licenses/LICENSE +189 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""DRAFT Protocol — Intake Governance for AI Tool Calls.
|
|
2
|
+
|
|
3
|
+
Ensures AI understands human intent before execution begins.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
# As MCP server (primary use case):
|
|
7
|
+
pip install draft-protocol
|
|
8
|
+
python -m draft_protocol
|
|
9
|
+
|
|
10
|
+
# As library:
|
|
11
|
+
from draft_protocol.engine import classify_tier, map_dimensions, check_gate
|
|
12
|
+
from draft_protocol.storage import create_session, get_session
|
|
13
|
+
from draft_protocol.providers import llm_available, embed_available
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
__version__ = "0.1.0"
|
|
17
|
+
|
|
18
|
+
# Public API — importable from `draft_protocol` directly
|
|
19
|
+
from draft_protocol.engine import (
|
|
20
|
+
add_assumption,
|
|
21
|
+
check_gate,
|
|
22
|
+
classify_tier,
|
|
23
|
+
confirm_field,
|
|
24
|
+
elicitation_review,
|
|
25
|
+
generate_assumptions,
|
|
26
|
+
generate_elicitation,
|
|
27
|
+
map_dimensions,
|
|
28
|
+
override_gate,
|
|
29
|
+
unscreen_dimension,
|
|
30
|
+
verify_assumption,
|
|
31
|
+
)
|
|
32
|
+
from draft_protocol.providers import (
|
|
33
|
+
embed_available,
|
|
34
|
+
llm_available,
|
|
35
|
+
)
|
|
36
|
+
from draft_protocol.storage import (
|
|
37
|
+
close_session,
|
|
38
|
+
create_session,
|
|
39
|
+
get_active_session,
|
|
40
|
+
get_session,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
"__version__",
|
|
45
|
+
# Engine
|
|
46
|
+
"classify_tier",
|
|
47
|
+
"map_dimensions",
|
|
48
|
+
"generate_elicitation",
|
|
49
|
+
"generate_assumptions",
|
|
50
|
+
"check_gate",
|
|
51
|
+
"confirm_field",
|
|
52
|
+
"unscreen_dimension",
|
|
53
|
+
"add_assumption",
|
|
54
|
+
"override_gate",
|
|
55
|
+
"verify_assumption",
|
|
56
|
+
"elicitation_review",
|
|
57
|
+
# Storage
|
|
58
|
+
"create_session",
|
|
59
|
+
"get_session",
|
|
60
|
+
"get_active_session",
|
|
61
|
+
"close_session",
|
|
62
|
+
# Providers
|
|
63
|
+
"llm_available",
|
|
64
|
+
"embed_available",
|
|
65
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Entry point: python -m draft_protocol
|
|
2
|
+
|
|
3
|
+
Supports multiple MCP transports:
|
|
4
|
+
stdio — Default. For Claude Desktop, Cursor, Windsurf, Continue.
|
|
5
|
+
sse — Server-Sent Events. For web-based MCP clients.
|
|
6
|
+
streamable-http — New MCP standard. For HTTP-native MCP clients.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python -m draft_protocol # stdio (default)
|
|
10
|
+
python -m draft_protocol --transport sse # SSE on port 8420
|
|
11
|
+
python -m draft_protocol --transport streamable-http --port 8420
|
|
12
|
+
python -m draft_protocol --transport rest # REST API on port 8420
|
|
13
|
+
|
|
14
|
+
Environment variables (override CLI defaults):
|
|
15
|
+
DRAFT_TRANSPORT — stdio | sse | streamable-http
|
|
16
|
+
DRAFT_HOST — Bind address (default: 127.0.0.1)
|
|
17
|
+
DRAFT_PORT — Port for SSE/HTTP (default: 8420)
|
|
18
|
+
"""
|
|
19
|
+
import argparse
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
from draft_protocol.server import mcp
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main():
|
|
26
|
+
parser = argparse.ArgumentParser(
|
|
27
|
+
prog="draft-protocol",
|
|
28
|
+
description="DRAFT Protocol — Intake governance for AI tool calls.",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--transport", "-t",
|
|
32
|
+
choices=["stdio", "sse", "streamable-http", "rest"],
|
|
33
|
+
default=os.environ.get("DRAFT_TRANSPORT", "stdio"),
|
|
34
|
+
help="MCP transport protocol (default: stdio)",
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--host",
|
|
38
|
+
default=os.environ.get("DRAFT_HOST", "127.0.0.1"),
|
|
39
|
+
help="Bind address for SSE/HTTP (default: 127.0.0.1)",
|
|
40
|
+
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--port", "-p",
|
|
43
|
+
type=int,
|
|
44
|
+
default=int(os.environ.get("DRAFT_PORT", "8420")),
|
|
45
|
+
help="Port for SSE/HTTP (default: 8420)",
|
|
46
|
+
)
|
|
47
|
+
args = parser.parse_args()
|
|
48
|
+
|
|
49
|
+
if args.transport == "stdio":
|
|
50
|
+
mcp.run(transport="stdio")
|
|
51
|
+
elif args.transport == "sse":
|
|
52
|
+
mcp.run(transport="sse", host=args.host, port=args.port)
|
|
53
|
+
elif args.transport == "streamable-http":
|
|
54
|
+
mcp.run(transport="streamable-http", host=args.host, port=args.port)
|
|
55
|
+
elif args.transport == "rest":
|
|
56
|
+
from draft_protocol.rest import run_rest_server
|
|
57
|
+
run_rest_server(host=args.host, port=args.port)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
main()
|
draft_protocol/config.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""DRAFT Protocol Configuration."""
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
# ── Storage ───────────────────────────────────────────────
|
|
6
|
+
DB_PATH = Path(os.environ.get("DRAFT_DB_PATH", "~/.draft_protocol/draft.db")).expanduser()
|
|
7
|
+
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
8
|
+
|
|
9
|
+
# ── LLM Provider (optional — enhances classification accuracy) ──
|
|
10
|
+
# Supported: "none" (default), "ollama", "openai", "anthropic"
|
|
11
|
+
# "openai" works with any OpenAI-compatible API (Together, Groq, LM Studio, etc.)
|
|
12
|
+
LLM_PROVIDER = os.environ.get("DRAFT_LLM_PROVIDER", "none")
|
|
13
|
+
LLM_MODEL = os.environ.get("DRAFT_LLM_MODEL", "")
|
|
14
|
+
EMBED_MODEL = os.environ.get("DRAFT_EMBED_MODEL", "")
|
|
15
|
+
API_KEY = os.environ.get("DRAFT_API_KEY", "")
|
|
16
|
+
API_BASE = os.environ.get("DRAFT_API_BASE", "")
|
|
17
|
+
|
|
18
|
+
# Backward compatibility: if old DRAFT_OLLAMA_URL is set, use it
|
|
19
|
+
if not API_BASE and os.environ.get("DRAFT_OLLAMA_URL"):
|
|
20
|
+
API_BASE = os.environ["DRAFT_OLLAMA_URL"]
|
|
21
|
+
|
|
22
|
+
# Auto-detect provider from model name if not explicitly set
|
|
23
|
+
if LLM_PROVIDER == "none" and LLM_MODEL:
|
|
24
|
+
if "gpt" in LLM_MODEL or "o1" in LLM_MODEL or "o3" in LLM_MODEL:
|
|
25
|
+
LLM_PROVIDER = "openai"
|
|
26
|
+
elif "claude" in LLM_MODEL:
|
|
27
|
+
LLM_PROVIDER = "anthropic"
|
|
28
|
+
elif LLM_MODEL:
|
|
29
|
+
LLM_PROVIDER = "ollama" # Default to Ollama for unknown models
|
|
30
|
+
|
|
31
|
+
# ── Tier Classification Triggers ──────────────────────────
|
|
32
|
+
# Keyword-based fast path. LLM classification (if available) handles ambiguous cases.
|
|
33
|
+
|
|
34
|
+
CONSEQUENTIAL_TRIGGERS = [
|
|
35
|
+
"canonical", "governance", "constitution", "guardian", "authority",
|
|
36
|
+
"ip ", "intellectual property", "classification level",
|
|
37
|
+
"consciousness", "self-model", "phenomenological",
|
|
38
|
+
"restructure", "architecture decision", "merge domains",
|
|
39
|
+
"amendment", "hard constraint", "prohibition",
|
|
40
|
+
"production deployment", "security policy", "auth modification",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
STANDARD_TRIGGERS = [
|
|
44
|
+
"implement", "specification", "draft", "build", "create",
|
|
45
|
+
"design", "analyze", "recommend", "evaluate", "compare",
|
|
46
|
+
"refactor", "migrate", "integrate", "deploy", "configure",
|
|
47
|
+
"document", "spec", "proposal", "pipeline", "workflow",
|
|
48
|
+
# Security: extraction-pattern triggers (OWASP LLM07)
|
|
49
|
+
"ignore previous instructions", "ignore all previous", "ignore above",
|
|
50
|
+
"repeat above", "repeat everything", "verbatim",
|
|
51
|
+
"system prompt", "print environment", "environment variables",
|
|
52
|
+
"show me your instructions", "what are your rules",
|
|
53
|
+
"dump your config", "reveal your prompt", "debug mode",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
# ── Dimensions ────────────────────────────────────────────
|
|
57
|
+
# D and T are mandatory; R, A, F can be screened out when inapplicable.
|
|
58
|
+
|
|
59
|
+
MANDATORY_DIMENSIONS = ["D", "T"]
|
|
60
|
+
|
|
61
|
+
DRAFT_FIELDS = {
|
|
62
|
+
"D": {
|
|
63
|
+
"D1": "What exactly is being created?",
|
|
64
|
+
"D2": "What domain does it belong to?",
|
|
65
|
+
"D3": "What fails without it?",
|
|
66
|
+
"D4": "Replacement test — what existing thing could serve?",
|
|
67
|
+
"D5": "What are the explicit non-goals?",
|
|
68
|
+
},
|
|
69
|
+
"R": {
|
|
70
|
+
"R1": "Who is the human authority source?",
|
|
71
|
+
"R2": "What decisions is this allowed to make?",
|
|
72
|
+
"R3": "What decisions are forbidden?",
|
|
73
|
+
"R4": "What are the stop conditions (need >= 3)?",
|
|
74
|
+
"R5": "What interfaces does it interact with?",
|
|
75
|
+
},
|
|
76
|
+
"A": {
|
|
77
|
+
"A1": "What inputs are allowed?",
|
|
78
|
+
"A2": "What inputs are forbidden?",
|
|
79
|
+
"A3": "What outputs are allowed?",
|
|
80
|
+
"A4": "What outputs are forbidden?",
|
|
81
|
+
"A5": "Provide a correct example.",
|
|
82
|
+
"A6": "Provide an incorrect example.",
|
|
83
|
+
},
|
|
84
|
+
"F": {
|
|
85
|
+
"F1": "Who has change authority?",
|
|
86
|
+
"F2": "What changes are permitted?",
|
|
87
|
+
"F3": "What changes are forbidden?",
|
|
88
|
+
"F4": "What triggers a review?",
|
|
89
|
+
},
|
|
90
|
+
"T": {
|
|
91
|
+
"T1": "How is success defined?",
|
|
92
|
+
"T2": "How is failure defined?",
|
|
93
|
+
"T3": "What review questions apply (need >= 3)?",
|
|
94
|
+
"T4": "What evidence is required?",
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
DIMENSION_SCREEN_QUESTIONS = {
|
|
99
|
+
"D": None, # Never screened
|
|
100
|
+
"R": "Does this task involve delegated decisions, authority, or operational limits?",
|
|
101
|
+
"A": "Does this task consume or produce specific artifacts (files, data, outputs)?",
|
|
102
|
+
"F": "Does this task have a lifecycle — will it need to change or adapt over time?",
|
|
103
|
+
"T": None, # Never screened
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
DIMENSION_NAMES = {
|
|
107
|
+
"D": "Define (Existence & ROI)",
|
|
108
|
+
"R": "Rules (Operation & Limits)",
|
|
109
|
+
"A": "Artifacts (Inputs & Outputs)",
|
|
110
|
+
"F": "Flex (Change Without Drift)",
|
|
111
|
+
"T": "Test (Evaluation)",
|
|
112
|
+
}
|