apcore-toolkit 0.1.0__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.
- apcore_toolkit-0.1.0/.github/CODEOWNERS +3 -0
- apcore_toolkit-0.1.0/.github/copilot-ignore +13 -0
- apcore_toolkit-0.1.0/.github/workflows/ci.yml +50 -0
- apcore_toolkit-0.1.0/.gitignore +18 -0
- apcore_toolkit-0.1.0/.gitmessage +60 -0
- apcore_toolkit-0.1.0/.pre-commit-config.yaml +27 -0
- apcore_toolkit-0.1.0/CHANGELOG.md +35 -0
- apcore_toolkit-0.1.0/PKG-INFO +150 -0
- apcore_toolkit-0.1.0/README.md +127 -0
- apcore_toolkit-0.1.0/docs/AI_ENHANCEMENT.md +56 -0
- apcore_toolkit-0.1.0/pyproject.toml +64 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/__init__.py +27 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/formatting/__init__.py +7 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/formatting/markdown.py +271 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/openapi.py +122 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/output/__init__.py +31 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/output/python_writer.py +177 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/output/registry_writer.py +85 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/output/yaml_writer.py +112 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/pydantic_utils.py +131 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/scanner.py +134 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/schema_utils.py +52 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/serializers.py +78 -0
- apcore_toolkit-0.1.0/src/apcore_toolkit/types.py +46 -0
- apcore_toolkit-0.1.0/tests/conftest.py +42 -0
- apcore_toolkit-0.1.0/tests/test_markdown.py +196 -0
- apcore_toolkit-0.1.0/tests/test_openapi.py +189 -0
- apcore_toolkit-0.1.0/tests/test_output_factory.py +32 -0
- apcore_toolkit-0.1.0/tests/test_pydantic_utils.py +120 -0
- apcore_toolkit-0.1.0/tests/test_python_writer.py +132 -0
- apcore_toolkit-0.1.0/tests/test_registry_writer.py +65 -0
- apcore_toolkit-0.1.0/tests/test_scanner.py +194 -0
- apcore_toolkit-0.1.0/tests/test_schema_utils.py +74 -0
- apcore_toolkit-0.1.0/tests/test_serializers.py +120 -0
- apcore_toolkit-0.1.0/tests/test_types.py +124 -0
- apcore_toolkit-0.1.0/tests/test_yaml_writer.py +90 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [ "main" ]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [ "main" ]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Test on Python ${{ matrix.python-version }}
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
# container:
|
|
17
|
+
# image: python:${{ matrix.python-version }}
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
# Pin CI to a single, consistent Python version to reduce version-related
|
|
22
|
+
# test flakiness. Use 3.12 for CI stability; expand matrix later if desired.
|
|
23
|
+
python-version: ["3.12"]
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
27
|
+
|
|
28
|
+
- name: Set up Python
|
|
29
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
cache: pip
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: |
|
|
36
|
+
python -m pip install --upgrade pip
|
|
37
|
+
# If a constraints.txt file is present, use it to pin critical dependency versions.
|
|
38
|
+
if [ -f constraints.txt ]; then
|
|
39
|
+
pip install -e ".[dev]" -c constraints.txt
|
|
40
|
+
else
|
|
41
|
+
pip install -e ".[dev]"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
- name: Lint with Ruff
|
|
45
|
+
run: |
|
|
46
|
+
ruff check src/ tests/
|
|
47
|
+
|
|
48
|
+
- name: Run tests
|
|
49
|
+
run: |
|
|
50
|
+
pytest
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# <type>(<scope>): <subject>
|
|
2
|
+
#
|
|
3
|
+
# <body>
|
|
4
|
+
#
|
|
5
|
+
# <footer>
|
|
6
|
+
|
|
7
|
+
# Type must be one of the following:
|
|
8
|
+
# feat: A new feature
|
|
9
|
+
# fix: A bug fix
|
|
10
|
+
# docs: Documentation only changes
|
|
11
|
+
# style: Changes that do not affect the meaning of the code
|
|
12
|
+
# refactor: A code change that neither fixes a bug nor adds a feature
|
|
13
|
+
# perf: A code change that improves performance
|
|
14
|
+
# test: Adding missing tests or correcting existing tests
|
|
15
|
+
# chore: Changes to the build process or auxiliary tools
|
|
16
|
+
# ci: Changes to CI configuration files and scripts
|
|
17
|
+
|
|
18
|
+
# Scope is optional and can be anything specifying the place of the commit change.
|
|
19
|
+
# Examples: api, core, storage, cli, stdio, etc.
|
|
20
|
+
|
|
21
|
+
# Subject should be:
|
|
22
|
+
# - Use imperative, present tense: "change" not "changed" nor "changes"
|
|
23
|
+
# - Don't capitalize first letter
|
|
24
|
+
# - No dot (.) at the end
|
|
25
|
+
# - Maximum 72 characters
|
|
26
|
+
|
|
27
|
+
# Body should include:
|
|
28
|
+
# - Motivation for the change and contrast with previous behavior
|
|
29
|
+
# - What changed and why
|
|
30
|
+
# - Any breaking changes
|
|
31
|
+
|
|
32
|
+
# Footer should contain:
|
|
33
|
+
# - Breaking changes (start with BREAKING CHANGE:)
|
|
34
|
+
# - Issue references (Closes #123, Fixes #456)
|
|
35
|
+
|
|
36
|
+
# Examples:
|
|
37
|
+
# feat(stdio): add stdio executor for process execution
|
|
38
|
+
#
|
|
39
|
+
# Implement a new stdio executor that allows executing system commands
|
|
40
|
+
# and processes via stdin/stdout communication, similar to MCP stdio
|
|
41
|
+
# transport mode. This enables flexible task execution through shell
|
|
42
|
+
# commands and Python scripts.
|
|
43
|
+
#
|
|
44
|
+
# - Add StdioExecutor class with command execution support
|
|
45
|
+
# - Add system resource monitoring (CPU, memory, disk)
|
|
46
|
+
# - Support async process communication
|
|
47
|
+
# - Add comprehensive error handling and logging
|
|
48
|
+
#
|
|
49
|
+
# Closes #123
|
|
50
|
+
|
|
51
|
+
# refactor(core): extract shared types to core.types module
|
|
52
|
+
#
|
|
53
|
+
# Move common type definitions from various modules to a centralized
|
|
54
|
+
# core.types module to avoid circular dependencies and improve code
|
|
55
|
+
# organization.
|
|
56
|
+
#
|
|
57
|
+
# - Add TaskPreHook and TaskPostHook type aliases
|
|
58
|
+
# - Move TaskStatus enum to core.types
|
|
59
|
+
# - Update imports across affected modules
|
|
60
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
|
|
3
|
+
# apdev hooks
|
|
4
|
+
- repo: local
|
|
5
|
+
hooks:
|
|
6
|
+
- id: check-chars
|
|
7
|
+
name: apdev check-chars
|
|
8
|
+
entry: apdev check-chars
|
|
9
|
+
language: system
|
|
10
|
+
types_or: [text, python]
|
|
11
|
+
|
|
12
|
+
- id: check-imports
|
|
13
|
+
name: apdev check-imports
|
|
14
|
+
entry: apdev check-imports
|
|
15
|
+
language: system
|
|
16
|
+
pass_filenames: false
|
|
17
|
+
always_run: true
|
|
18
|
+
|
|
19
|
+
# Ruff linter and formatter
|
|
20
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
21
|
+
rev: v0.8.4
|
|
22
|
+
hooks:
|
|
23
|
+
- id: ruff
|
|
24
|
+
args: [--fix]
|
|
25
|
+
files: ^(src|tests)/
|
|
26
|
+
- id: ruff-format
|
|
27
|
+
files: ^(src|tests)/
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-03-06
|
|
6
|
+
|
|
7
|
+
Initial release. Extracts shared framework-agnostic logic from `django-apcore`
|
|
8
|
+
and `flask-apcore` into a standalone toolkit package.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `ScannedModule` dataclass — canonical representation of a scanned endpoint
|
|
13
|
+
- `BaseScanner` ABC with `filter_modules()`, `deduplicate_ids()`,
|
|
14
|
+
`infer_annotations_from_method()`, and `extract_docstring()` utilities
|
|
15
|
+
- `YAMLWriter` — generates `.binding.yaml` files for `apcore.BindingLoader`
|
|
16
|
+
- `PythonWriter` — generates `@module`-decorated Python wrapper files
|
|
17
|
+
- `RegistryWriter` — registers modules directly into `apcore.Registry`
|
|
18
|
+
- `to_markdown()` — generic dict-to-Markdown conversion with depth control
|
|
19
|
+
and table heuristics
|
|
20
|
+
- `flatten_pydantic_params()` — flattens Pydantic model parameters into
|
|
21
|
+
scalar kwargs for MCP tool invocation
|
|
22
|
+
- `resolve_target()` — resolves `module.path:qualname` target strings
|
|
23
|
+
- `enrich_schema_descriptions()` — merges docstring parameter descriptions
|
|
24
|
+
into JSON Schema properties
|
|
25
|
+
- `annotations_to_dict()` / `module_to_dict()` — serialization utilities
|
|
26
|
+
- OpenAPI utilities: `resolve_ref()`, `resolve_schema()`,
|
|
27
|
+
`extract_input_schema()`, `extract_output_schema()`
|
|
28
|
+
- Output format factory via `get_writer()`
|
|
29
|
+
- 150 tests with 94% code coverage
|
|
30
|
+
|
|
31
|
+
### Dependencies
|
|
32
|
+
|
|
33
|
+
- apcore >= 0.9.0
|
|
34
|
+
- pydantic >= 2.0
|
|
35
|
+
- PyYAML >= 6.0
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apcore-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Shared scanner, schema extraction, and output toolkit for apcore framework adapters
|
|
5
|
+
Project-URL: Homepage, https://aipartnerup.com
|
|
6
|
+
Project-URL: Repository, https://github.com/aipartnerup/apcore-toolkit-python
|
|
7
|
+
Project-URL: Documentation, https://github.com/aipartnerup/apcore-toolkit-python#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/aipartnerup/apcore-toolkit-python/issues
|
|
9
|
+
Author-email: aipartnerup <tercel.yi@gmail.com>
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Keywords: apcore,mcp,openapi,pydantic,scanner,schema,toolkit,yaml
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Requires-Dist: apcore>=0.9.0
|
|
14
|
+
Requires-Dist: pydantic>=2.0
|
|
15
|
+
Requires-Dist: pyyaml>=6.0
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: apdev[dev]>=0.2.0; extra == 'dev'
|
|
18
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# apcore-toolkit
|
|
25
|
+
|
|
26
|
+
Shared scanner, schema extraction, and output toolkit for [apcore](https://github.com/aipartnerup/apcore-python) Python framework adapters.
|
|
27
|
+
|
|
28
|
+
Extracts ~1,400 lines of duplicated framework-agnostic logic from `django-apcore` and `flask-apcore` into a standalone Python package.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install apcore-toolkit
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Core Modules
|
|
37
|
+
|
|
38
|
+
| Module | Description |
|
|
39
|
+
|--------|-------------|
|
|
40
|
+
| `ScannedModule` | Canonical dataclass representing a scanned endpoint |
|
|
41
|
+
| `BaseScanner` | Abstract base class for framework scanners with filtering and deduplication |
|
|
42
|
+
| `YAMLWriter` | Generates `.binding.yaml` files for `apcore.BindingLoader` |
|
|
43
|
+
| `PythonWriter` | Generates `@module`-decorated Python wrapper files |
|
|
44
|
+
| `RegistryWriter` | Registers modules directly into an `apcore.Registry` |
|
|
45
|
+
| `to_markdown` | Converts arbitrary dicts to Markdown with depth control and table heuristics |
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### Scanning and Writing
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from apcore_toolkit import BaseScanner, ScannedModule, YAMLWriter
|
|
53
|
+
|
|
54
|
+
class MyScanner(BaseScanner):
|
|
55
|
+
def scan(self, **kwargs):
|
|
56
|
+
# Scan your framework endpoints and return ScannedModule instances
|
|
57
|
+
return [
|
|
58
|
+
ScannedModule(
|
|
59
|
+
module_id="users.get_user",
|
|
60
|
+
description="Get a user by ID",
|
|
61
|
+
input_schema={"type": "object", "properties": {"id": {"type": "integer"}}, "required": ["id"]},
|
|
62
|
+
output_schema={"type": "object", "properties": {"name": {"type": "string"}}},
|
|
63
|
+
tags=["users"],
|
|
64
|
+
target="myapp.views:get_user",
|
|
65
|
+
)
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
def get_source_name(self):
|
|
69
|
+
return "my-framework"
|
|
70
|
+
|
|
71
|
+
scanner = MyScanner()
|
|
72
|
+
modules = scanner.scan()
|
|
73
|
+
|
|
74
|
+
# Filter and deduplicate
|
|
75
|
+
modules = scanner.filter_modules(modules, include=r"^users\.")
|
|
76
|
+
modules = scanner.deduplicate_ids(modules)
|
|
77
|
+
|
|
78
|
+
# Write YAML binding files
|
|
79
|
+
writer = YAMLWriter()
|
|
80
|
+
writer.write(modules, output_dir="./bindings")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Direct Registry Registration
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from apcore import Registry
|
|
87
|
+
from apcore_toolkit import RegistryWriter
|
|
88
|
+
|
|
89
|
+
registry = Registry()
|
|
90
|
+
writer = RegistryWriter()
|
|
91
|
+
writer.write(modules, registry)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Output Format Factory
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from apcore_toolkit.output import get_writer
|
|
98
|
+
|
|
99
|
+
writer = get_writer("yaml") # YAMLWriter
|
|
100
|
+
writer = get_writer("python") # PythonWriter
|
|
101
|
+
writer = get_writer("registry") # RegistryWriter
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Pydantic Model Flattening
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from apcore_toolkit import flatten_pydantic_params, resolve_target
|
|
108
|
+
|
|
109
|
+
# Resolve a target string to a callable
|
|
110
|
+
func = resolve_target("myapp.views:create_task")
|
|
111
|
+
|
|
112
|
+
# Flatten Pydantic model params into scalar kwargs for MCP tools
|
|
113
|
+
wrapped = flatten_pydantic_params(func)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### OpenAPI Schema Extraction
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from apcore_toolkit.openapi import extract_input_schema, extract_output_schema
|
|
120
|
+
|
|
121
|
+
input_schema = extract_input_schema(operation, openapi_doc)
|
|
122
|
+
output_schema = extract_output_schema(operation, openapi_doc)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Schema Enrichment
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from apcore_toolkit import enrich_schema_descriptions
|
|
129
|
+
|
|
130
|
+
enriched = enrich_schema_descriptions(schema, {"user_id": "The user ID"})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Markdown Formatting
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from apcore_toolkit import to_markdown
|
|
137
|
+
|
|
138
|
+
md = to_markdown({"name": "Alice", "role": "admin"}, title="User Info")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Requirements
|
|
142
|
+
|
|
143
|
+
- Python >= 3.11
|
|
144
|
+
- apcore >= 0.9.0
|
|
145
|
+
- pydantic >= 2.0
|
|
146
|
+
- PyYAML >= 6.0
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
Apache-2.0
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# apcore-toolkit
|
|
2
|
+
|
|
3
|
+
Shared scanner, schema extraction, and output toolkit for [apcore](https://github.com/aipartnerup/apcore-python) Python framework adapters.
|
|
4
|
+
|
|
5
|
+
Extracts ~1,400 lines of duplicated framework-agnostic logic from `django-apcore` and `flask-apcore` into a standalone Python package.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install apcore-toolkit
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Core Modules
|
|
14
|
+
|
|
15
|
+
| Module | Description |
|
|
16
|
+
|--------|-------------|
|
|
17
|
+
| `ScannedModule` | Canonical dataclass representing a scanned endpoint |
|
|
18
|
+
| `BaseScanner` | Abstract base class for framework scanners with filtering and deduplication |
|
|
19
|
+
| `YAMLWriter` | Generates `.binding.yaml` files for `apcore.BindingLoader` |
|
|
20
|
+
| `PythonWriter` | Generates `@module`-decorated Python wrapper files |
|
|
21
|
+
| `RegistryWriter` | Registers modules directly into an `apcore.Registry` |
|
|
22
|
+
| `to_markdown` | Converts arbitrary dicts to Markdown with depth control and table heuristics |
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Scanning and Writing
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from apcore_toolkit import BaseScanner, ScannedModule, YAMLWriter
|
|
30
|
+
|
|
31
|
+
class MyScanner(BaseScanner):
|
|
32
|
+
def scan(self, **kwargs):
|
|
33
|
+
# Scan your framework endpoints and return ScannedModule instances
|
|
34
|
+
return [
|
|
35
|
+
ScannedModule(
|
|
36
|
+
module_id="users.get_user",
|
|
37
|
+
description="Get a user by ID",
|
|
38
|
+
input_schema={"type": "object", "properties": {"id": {"type": "integer"}}, "required": ["id"]},
|
|
39
|
+
output_schema={"type": "object", "properties": {"name": {"type": "string"}}},
|
|
40
|
+
tags=["users"],
|
|
41
|
+
target="myapp.views:get_user",
|
|
42
|
+
)
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
def get_source_name(self):
|
|
46
|
+
return "my-framework"
|
|
47
|
+
|
|
48
|
+
scanner = MyScanner()
|
|
49
|
+
modules = scanner.scan()
|
|
50
|
+
|
|
51
|
+
# Filter and deduplicate
|
|
52
|
+
modules = scanner.filter_modules(modules, include=r"^users\.")
|
|
53
|
+
modules = scanner.deduplicate_ids(modules)
|
|
54
|
+
|
|
55
|
+
# Write YAML binding files
|
|
56
|
+
writer = YAMLWriter()
|
|
57
|
+
writer.write(modules, output_dir="./bindings")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Direct Registry Registration
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from apcore import Registry
|
|
64
|
+
from apcore_toolkit import RegistryWriter
|
|
65
|
+
|
|
66
|
+
registry = Registry()
|
|
67
|
+
writer = RegistryWriter()
|
|
68
|
+
writer.write(modules, registry)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Output Format Factory
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from apcore_toolkit.output import get_writer
|
|
75
|
+
|
|
76
|
+
writer = get_writer("yaml") # YAMLWriter
|
|
77
|
+
writer = get_writer("python") # PythonWriter
|
|
78
|
+
writer = get_writer("registry") # RegistryWriter
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Pydantic Model Flattening
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from apcore_toolkit import flatten_pydantic_params, resolve_target
|
|
85
|
+
|
|
86
|
+
# Resolve a target string to a callable
|
|
87
|
+
func = resolve_target("myapp.views:create_task")
|
|
88
|
+
|
|
89
|
+
# Flatten Pydantic model params into scalar kwargs for MCP tools
|
|
90
|
+
wrapped = flatten_pydantic_params(func)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### OpenAPI Schema Extraction
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from apcore_toolkit.openapi import extract_input_schema, extract_output_schema
|
|
97
|
+
|
|
98
|
+
input_schema = extract_input_schema(operation, openapi_doc)
|
|
99
|
+
output_schema = extract_output_schema(operation, openapi_doc)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Schema Enrichment
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from apcore_toolkit import enrich_schema_descriptions
|
|
106
|
+
|
|
107
|
+
enriched = enrich_schema_descriptions(schema, {"user_id": "The user ID"})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Markdown Formatting
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from apcore_toolkit import to_markdown
|
|
114
|
+
|
|
115
|
+
md = to_markdown({"name": "Alice", "role": "admin"}, title="User Info")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Requirements
|
|
119
|
+
|
|
120
|
+
- Python >= 3.11
|
|
121
|
+
- apcore >= 0.9.0
|
|
122
|
+
- pydantic >= 2.0
|
|
123
|
+
- PyYAML >= 6.0
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
Apache-2.0
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# AI-Driven Metadata Enhancement for apcore-toolkit
|
|
2
|
+
|
|
3
|
+
This document outlines the strategy for using Small Language Models (SLMs) like **Qwen 1.5 (0.6B - 1.7B)** to enhance the metadata extracted by `apcore-toolkit-python`.
|
|
4
|
+
|
|
5
|
+
## 1. Goal
|
|
6
|
+
|
|
7
|
+
The toolkit's primary mission is to make existing code "AI-Perceivable". While static analysis (regex, AST) is efficient, it often fails to:
|
|
8
|
+
- Generate meaningful `description` and `documentation` for legacy code.
|
|
9
|
+
- Create effective `ai_guidance` for complex error handling.
|
|
10
|
+
- Infer `input_schema` for functions using `*args` or `**kwargs`.
|
|
11
|
+
|
|
12
|
+
Using a local SLM allows the toolkit to "understand" the code logic and fill these gaps with high speed and zero cost.
|
|
13
|
+
|
|
14
|
+
## 2. Architecture: Local LLM Provider (Option B)
|
|
15
|
+
|
|
16
|
+
To keep `apcore-toolkit-python` lightweight, we **DO NOT** bundle model weights. Instead, we use an OpenAI-compatible local API provider (e.g., Ollama, vLLM, LM Studio).
|
|
17
|
+
|
|
18
|
+
### Configuration via Environment Variables
|
|
19
|
+
|
|
20
|
+
The AI enhancement feature is controlled by the following environment variables:
|
|
21
|
+
|
|
22
|
+
| Variable | Description | Default |
|
|
23
|
+
|----------|-------------|---------|
|
|
24
|
+
| `APCORE_AI_ENABLED` | Whether to enable SLM-based metadata enhancement. | `false` |
|
|
25
|
+
| `APCORE_AI_ENDPOINT` | The URL of the OpenAI-compatible local API. | `http://localhost:11434/v1` |
|
|
26
|
+
| `APCORE_AI_MODEL` | The model name to use (e.g., `qwen:0.6b`). | `qwen:0.6b` |
|
|
27
|
+
| `APCORE_AI_THRESHOLD` | Confidence threshold for AI-generated metadata (0-1). | `0.7` |
|
|
28
|
+
|
|
29
|
+
## 3. Recommended Setup (Ollama)
|
|
30
|
+
|
|
31
|
+
For the best developer experience, we recommend using [Ollama](https://ollama.com/):
|
|
32
|
+
|
|
33
|
+
1. **Install Ollama**.
|
|
34
|
+
2. **Pull the recommended model**:
|
|
35
|
+
```bash
|
|
36
|
+
ollama run qwen:0.6b
|
|
37
|
+
```
|
|
38
|
+
3. **Configure environment**:
|
|
39
|
+
```bash
|
|
40
|
+
export APCORE_AI_ENABLED=true
|
|
41
|
+
export APCORE_AI_MODEL="qwen:0.6b"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 4. Enhancement Workflow
|
|
45
|
+
|
|
46
|
+
When `APCORE_AI_ENABLED` is set to `true`, the `Scanner` will:
|
|
47
|
+
|
|
48
|
+
1. **Extract static metadata** from docstrings and type hints.
|
|
49
|
+
2. **Identify missing fields** (e.g., empty `description` or missing `ai_guidance`).
|
|
50
|
+
3. **Send code snippets** to the local SLM with a structured prompt.
|
|
51
|
+
4. **Merge the AI-generated metadata** into the final `ScannedModule`, marking them with a `x-generated-by: "slm"` tag for human audit.
|
|
52
|
+
|
|
53
|
+
## 5. Security and Privacy
|
|
54
|
+
|
|
55
|
+
- **No Data Leakage**: Since the model runs locally, your source code never leaves your machine.
|
|
56
|
+
- **Auditability**: All AI-generated fields MUST be reviewed by the developer before committing the generated `apcore.yaml`.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "apcore-toolkit"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Shared scanner, schema extraction, and output toolkit for apcore framework adapters"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "Apache-2.0"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "aipartnerup", email = "tercel.yi@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"apcore",
|
|
17
|
+
"mcp",
|
|
18
|
+
"scanner",
|
|
19
|
+
"schema",
|
|
20
|
+
"yaml",
|
|
21
|
+
"pydantic",
|
|
22
|
+
"openapi",
|
|
23
|
+
"toolkit",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"apcore>=0.9.0",
|
|
27
|
+
"pydantic>=2.0",
|
|
28
|
+
"PyYAML>=6.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = [
|
|
33
|
+
"pytest>=7.0",
|
|
34
|
+
"pytest-cov>=4.0",
|
|
35
|
+
"ruff>=0.1",
|
|
36
|
+
"mypy>=1.0",
|
|
37
|
+
"apdev[dev]>=0.2.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://aipartnerup.com"
|
|
42
|
+
Repository = "https://github.com/aipartnerup/apcore-toolkit-python"
|
|
43
|
+
Documentation = "https://github.com/aipartnerup/apcore-toolkit-python#readme"
|
|
44
|
+
Issues = "https://github.com/aipartnerup/apcore-toolkit-python/issues"
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.wheel]
|
|
47
|
+
packages = ["src/apcore_toolkit"]
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths = ["tests"]
|
|
51
|
+
pythonpath = ["src"]
|
|
52
|
+
|
|
53
|
+
[tool.ruff]
|
|
54
|
+
src = ["src"]
|
|
55
|
+
target-version = "py311"
|
|
56
|
+
line-length = 120
|
|
57
|
+
|
|
58
|
+
[tool.apdev]
|
|
59
|
+
base_package = "apcore_toolkit"
|
|
60
|
+
src_dir = "src"
|
|
61
|
+
|
|
62
|
+
[tool.mypy]
|
|
63
|
+
python_version = "3.11"
|
|
64
|
+
strict = true
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""apcore-toolkit — Shared scanner, schema extraction, and output toolkit.
|
|
2
|
+
|
|
3
|
+
Public API re-exports for convenient access to core types and utilities.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from apcore_toolkit.formatting import to_markdown
|
|
7
|
+
from apcore_toolkit.output.python_writer import PythonWriter
|
|
8
|
+
from apcore_toolkit.output.registry_writer import RegistryWriter
|
|
9
|
+
from apcore_toolkit.output.yaml_writer import YAMLWriter
|
|
10
|
+
from apcore_toolkit.pydantic_utils import flatten_pydantic_params, resolve_target
|
|
11
|
+
from apcore_toolkit.scanner import BaseScanner
|
|
12
|
+
from apcore_toolkit.schema_utils import enrich_schema_descriptions
|
|
13
|
+
from apcore_toolkit.types import ScannedModule
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"BaseScanner",
|
|
19
|
+
"PythonWriter",
|
|
20
|
+
"RegistryWriter",
|
|
21
|
+
"ScannedModule",
|
|
22
|
+
"YAMLWriter",
|
|
23
|
+
"enrich_schema_descriptions",
|
|
24
|
+
"flatten_pydantic_params",
|
|
25
|
+
"resolve_target",
|
|
26
|
+
"to_markdown",
|
|
27
|
+
]
|