ownapi 1.0.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.
- cli.py +1017 -0
- compiler.py +948 -0
- core/__init__.py +19 -0
- core/api_keys.py +523 -0
- core/auto_repair.py +682 -0
- core/base_client.py +165 -0
- core/consent.py +169 -0
- core/form_automation.py +1044 -0
- core/hitl_queue.py +886 -0
- core/onboarding.py +1457 -0
- core/token_store.py +223 -0
- healer.py +2074 -0
- master_mcp.py +193 -0
- ownapi/__init__.py +94 -0
- ownapi/cli.py +309 -0
- ownapi/sdk.py +436 -0
- ownapi-1.0.0.dist-info/METADATA +287 -0
- ownapi-1.0.0.dist-info/RECORD +62 -0
- ownapi-1.0.0.dist-info/WHEEL +5 -0
- ownapi-1.0.0.dist-info/entry_points.txt +4 -0
- ownapi-1.0.0.dist-info/top_level.txt +10 -0
- recorder.py +486 -0
- registry/coingecko/__init__.py +5 -0
- registry/coingecko/client.py +84 -0
- registry/coingecko/schema.json +23 -0
- registry/edevlet/__init__.py +5 -0
- registry/edevlet/client.py +54 -0
- registry/edevlet/schema.json +14 -0
- registry/enuygun/__init__.py +5 -0
- registry/enuygun/client.py +78 -0
- registry/enuygun/schema.json +13 -0
- registry/github_trending/__init__.py +5 -0
- registry/github_trending/client.py +90 -0
- registry/github_trending/schema.json +31 -0
- registry/hackernews/__init__.py +5 -0
- registry/hackernews/client.py +90 -0
- registry/hackernews/schema.json +38 -0
- registry/hepsiburada/__init__.py +5 -0
- registry/hepsiburada/client.py +32 -0
- registry/hepsiburada/schema.json +23 -0
- registry/linkedin_jobs/__init__.py +5 -0
- registry/linkedin_jobs/client.py +241 -0
- registry/linkedin_jobs/schema.json +46 -0
- registry/pegasus/__init__.py +5 -0
- registry/pegasus/client.py +141 -0
- registry/pegasus/schema.json +76 -0
- registry/thy/__init__.py +5 -0
- registry/thy/client.py +1796 -0
- registry/thy/schema.json +46 -0
- registry/trendyol/__init__.py +5 -0
- registry/trendyol/client.py +228 -0
- registry/trendyol/schema.json +30 -0
- registry/ucak_bileti/client.py +94 -0
- registry/ucak_bileti/schema.json +47 -0
- registry/wikipedia/__init__.py +5 -0
- registry/wikipedia/client.py +64 -0
- registry/wikipedia/schema.json +31 -0
- registry/yahoo_finance/__init__.py +5 -0
- registry/yahoo_finance/client.py +98 -0
- registry/yahoo_finance/schema.json +22 -0
- server.py +891 -0
- static/index.html +2401 -0
ownapi/sdk.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import inspect
|
|
5
|
+
import os
|
|
6
|
+
import pathlib
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Callable
|
|
10
|
+
|
|
11
|
+
PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[1]
|
|
12
|
+
if str(PROJECT_ROOT) not in sys.path:
|
|
13
|
+
sys.path.insert(0, str(PROJECT_ROOT))
|
|
14
|
+
|
|
15
|
+
from core.api_keys import (
|
|
16
|
+
APIKeyManager,
|
|
17
|
+
CreditBalance,
|
|
18
|
+
consume_credit,
|
|
19
|
+
generate_api_key,
|
|
20
|
+
get_or_create_tenant,
|
|
21
|
+
get_tenant_info,
|
|
22
|
+
upgrade_plan,
|
|
23
|
+
)
|
|
24
|
+
from core.auto_repair import AutoRepairEngine
|
|
25
|
+
from core.base_client import BaseOwnClient, BaseShadowClient
|
|
26
|
+
from core.consent import ConsentManager
|
|
27
|
+
from core.hitl_queue import HITLQueueManager
|
|
28
|
+
from core.onboarding import onboard_new_site
|
|
29
|
+
from core.token_store import TokenStore
|
|
30
|
+
from master_mcp import load_registry_tools
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _load_connector_module(service_name: str, registry_root: Path | None = None) -> Any:
|
|
34
|
+
"""`registry/<service_name>/client.py` modülünü dinamik olarak yükler ve döndürür."""
|
|
35
|
+
reg_dir = Path(registry_root) if registry_root else (PROJECT_ROOT / "registry")
|
|
36
|
+
clean_svc = service_name.strip().lower()
|
|
37
|
+
client_file = reg_dir / clean_svc / "client.py"
|
|
38
|
+
if not client_file.exists():
|
|
39
|
+
raise AttributeError(
|
|
40
|
+
f"OwnAPI konektörü bulunamadı: 'registry/{clean_svc}/client.py'"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
mod_name = f"ownapi_connector_{clean_svc}"
|
|
44
|
+
if mod_name in sys.modules:
|
|
45
|
+
return sys.modules[mod_name]
|
|
46
|
+
|
|
47
|
+
spec = importlib.util.spec_from_file_location(mod_name, str(client_file.resolve()))
|
|
48
|
+
if spec is None or spec.loader is None:
|
|
49
|
+
raise ImportError(f"Konektör modülü yüklenemedi: {client_file}")
|
|
50
|
+
module = importlib.util.module_from_spec(spec)
|
|
51
|
+
sys.modules[mod_name] = module
|
|
52
|
+
spec.loader.exec_module(module)
|
|
53
|
+
return module
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ServiceNamespaceProxy:
|
|
57
|
+
"""
|
|
58
|
+
`from ownapi import thy, trendyol, pegasus` veya `api.thy.search_flights(...)`
|
|
59
|
+
kullanımlarını yöneten akıllı servis vekil (proxy) sınıfı.
|
|
60
|
+
|
|
61
|
+
Her çağrıda:
|
|
62
|
+
1. `core/api_keys.py` üzerinden aktif kullanıcı (`default` veya `api_key` sahibi kiracı)
|
|
63
|
+
kredisinden `1` kredi düşer (`consume_credit`).
|
|
64
|
+
2. Kullanıcının paketine ait çalışma modunu (`mode="local"` veya `mode="cloud"`) ve
|
|
65
|
+
`tenant_id` bilgisini hedef konektör fonksiyonuna otomatik enjekte eder.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
service_name: str,
|
|
71
|
+
owner: OwnAPI | None = None,
|
|
72
|
+
default_tenant_id: str = "default",
|
|
73
|
+
default_mode: str = "local",
|
|
74
|
+
registry_root: Path | None = None,
|
|
75
|
+
state_file: Path | str | None = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
self._service_name = service_name.strip().lower()
|
|
78
|
+
self._owner = owner
|
|
79
|
+
self._default_tenant_id = default_tenant_id
|
|
80
|
+
self._default_mode = default_mode
|
|
81
|
+
self._registry_root = Path(registry_root) if registry_root else (PROJECT_ROOT / "registry")
|
|
82
|
+
self._state_file = state_file
|
|
83
|
+
self._module: Any = None
|
|
84
|
+
|
|
85
|
+
def _get_module(self) -> Any:
|
|
86
|
+
if self._module is None:
|
|
87
|
+
self._module = _load_connector_module(self._service_name, self._registry_root)
|
|
88
|
+
return self._module
|
|
89
|
+
|
|
90
|
+
def _resolve_execution_context(self) -> tuple[str, str, str | None, CreditBalance]:
|
|
91
|
+
"""
|
|
92
|
+
Çağrı öncesi `core/api_keys.py` üzerinden kredi düşümünü yapar ve
|
|
93
|
+
`(tenant_id, mode, api_key, credit_balance)` dörtlüsünü döndürür.
|
|
94
|
+
"""
|
|
95
|
+
if self._owner is not None:
|
|
96
|
+
auth_identifier = self._owner.api_key or self._owner.tenant_id
|
|
97
|
+
state_path = self._owner._state_file
|
|
98
|
+
info = get_tenant_info(auth_identifier, state_file=state_path)
|
|
99
|
+
balance = consume_credit(
|
|
100
|
+
auth_identifier,
|
|
101
|
+
amount=1,
|
|
102
|
+
state_file=state_path,
|
|
103
|
+
service=self._service_name,
|
|
104
|
+
)
|
|
105
|
+
active_tenant = str(info.get("tenant_id") or self._owner.tenant_id or "default")
|
|
106
|
+
active_mode = str(self._owner._explicit_mode or info.get("mode") or self._owner.mode or "local")
|
|
107
|
+
return active_tenant, active_mode, self._owner.api_key, balance
|
|
108
|
+
|
|
109
|
+
# Bedava yerel mod (`from ownapi import thy, trendyol, pegasus`)
|
|
110
|
+
info = get_or_create_tenant(self._default_tenant_id, state_file=self._state_file)
|
|
111
|
+
balance = consume_credit(
|
|
112
|
+
self._default_tenant_id,
|
|
113
|
+
amount=1,
|
|
114
|
+
state_file=self._state_file,
|
|
115
|
+
service=self._service_name,
|
|
116
|
+
)
|
|
117
|
+
active_tenant = str(info.get("tenant_id") or self._default_tenant_id)
|
|
118
|
+
active_mode = str(info.get("mode") or self._default_mode or "local")
|
|
119
|
+
return active_tenant, active_mode, info.get("api_key"), balance
|
|
120
|
+
|
|
121
|
+
def _resolve_callable(self, attr_name: str) -> Callable[..., Any]:
|
|
122
|
+
mod = self._get_module()
|
|
123
|
+
|
|
124
|
+
# 1. Doğrudan modül fonksiyonu varsa (örn. thy.search_flights, pegasus.get_flight_availability)
|
|
125
|
+
target = getattr(mod, attr_name, None)
|
|
126
|
+
if callable(target) and not inspect.isclass(target):
|
|
127
|
+
return target
|
|
128
|
+
|
|
129
|
+
# 2. Modül içindeki BaseOwnClient alt sınıfı üzerinde metot varsa (örn. trendyol.search)
|
|
130
|
+
client_cls = None
|
|
131
|
+
for _, obj in inspect.getmembers(mod, inspect.isclass):
|
|
132
|
+
if issubclass(obj, BaseOwnClient) and obj is not BaseOwnClient:
|
|
133
|
+
client_cls = obj
|
|
134
|
+
break
|
|
135
|
+
|
|
136
|
+
if client_cls is not None and hasattr(client_cls, attr_name):
|
|
137
|
+
def _bound_method_runner(
|
|
138
|
+
*args: Any,
|
|
139
|
+
tenant_id: str = "default",
|
|
140
|
+
mode: str = "local",
|
|
141
|
+
**kwargs: Any,
|
|
142
|
+
) -> Any:
|
|
143
|
+
init_sig = inspect.signature(client_cls.__init__)
|
|
144
|
+
init_kwargs: dict[str, Any] = {}
|
|
145
|
+
if "tenant_id" in init_sig.parameters:
|
|
146
|
+
init_kwargs["tenant_id"] = tenant_id
|
|
147
|
+
if "mode" in init_sig.parameters:
|
|
148
|
+
init_kwargs["mode"] = mode
|
|
149
|
+
instance = client_cls(**init_kwargs)
|
|
150
|
+
instance.tenant_id = tenant_id
|
|
151
|
+
instance.mode = mode
|
|
152
|
+
method_fn = getattr(instance, attr_name)
|
|
153
|
+
m_sig = inspect.signature(method_fn)
|
|
154
|
+
if "tenant_id" in m_sig.parameters:
|
|
155
|
+
kwargs["tenant_id"] = tenant_id
|
|
156
|
+
if "mode" in m_sig.parameters:
|
|
157
|
+
kwargs["mode"] = mode
|
|
158
|
+
return method_fn(*args, **kwargs)
|
|
159
|
+
|
|
160
|
+
return _bound_method_runner
|
|
161
|
+
|
|
162
|
+
# 3. Yaygın takma adlar (search / search_flights / call) için ana fonksiyonu bul
|
|
163
|
+
if attr_name in ("search", "search_flights", "get_flight_availability", "call"):
|
|
164
|
+
public_funcs = [
|
|
165
|
+
obj
|
|
166
|
+
for name, obj in inspect.getmembers(mod, inspect.isfunction)
|
|
167
|
+
if obj.__module__ == mod.__name__ and not name.startswith("_")
|
|
168
|
+
]
|
|
169
|
+
if public_funcs:
|
|
170
|
+
return public_funcs[0]
|
|
171
|
+
|
|
172
|
+
raise AttributeError(
|
|
173
|
+
f"'{self._service_name}' servisinde '{attr_name}' fonksiyonu bulunamadı."
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def __getattr__(self, name: str) -> Any:
|
|
177
|
+
if name.startswith("_"):
|
|
178
|
+
raise AttributeError(name)
|
|
179
|
+
|
|
180
|
+
mod = self._get_module()
|
|
181
|
+
raw_attr = getattr(mod, name, None)
|
|
182
|
+
if raw_attr is not None and not callable(raw_attr):
|
|
183
|
+
return raw_attr
|
|
184
|
+
|
|
185
|
+
target_fn = self._resolve_callable(name)
|
|
186
|
+
|
|
187
|
+
def _wrapped(*args: Any, **kwargs: Any) -> Any:
|
|
188
|
+
active_tenant, active_mode, _, _ = self._resolve_execution_context()
|
|
189
|
+
sig = inspect.signature(target_fn)
|
|
190
|
+
call_kwargs = dict(kwargs)
|
|
191
|
+
if "tenant_id" in sig.parameters and "tenant_id" not in call_kwargs:
|
|
192
|
+
call_kwargs["tenant_id"] = active_tenant
|
|
193
|
+
if "mode" in sig.parameters and "mode" not in call_kwargs:
|
|
194
|
+
call_kwargs["mode"] = active_mode
|
|
195
|
+
return target_fn(*args, **call_kwargs)
|
|
196
|
+
|
|
197
|
+
_wrapped.__name__ = name
|
|
198
|
+
_wrapped.__doc__ = getattr(target_fn, "__doc__", None)
|
|
199
|
+
return _wrapped
|
|
200
|
+
|
|
201
|
+
def __repr__(self) -> str:
|
|
202
|
+
mode_str = self._owner.mode if self._owner else self._default_mode
|
|
203
|
+
return f"<OwnAPI ServiceProxy '{self._service_name}' (mode='{mode_str}')>"
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class OwnAPI:
|
|
207
|
+
"""
|
|
208
|
+
OwnAPI Birleşik Python SDK İstemcisi (`from ownapi import OwnAPI`).
|
|
209
|
+
- Bedava Yerel Mod veya `$10` (`starter_cloud`) / `$49` (`growth_cloud`) bulut anahtarıyla çalışır:
|
|
210
|
+
`api = OwnAPI(api_key="sk-ownapi-...")`
|
|
211
|
+
`api.thy.search_flights(origin_airport_code="IST", destination_airport_code="ESB")`
|
|
212
|
+
`api.trendyol.search(query="laptop")`
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
def __init__(
|
|
216
|
+
self,
|
|
217
|
+
api_key: str | None = None,
|
|
218
|
+
tenant_id: str | None = None,
|
|
219
|
+
mode: str | None = None,
|
|
220
|
+
cloud_cdp_url: str | None = None,
|
|
221
|
+
non_interactive: bool = False,
|
|
222
|
+
registry_root: pathlib.Path | str = PROJECT_ROOT / "registry",
|
|
223
|
+
state_file: pathlib.Path | str | None = None,
|
|
224
|
+
**kwargs: Any,
|
|
225
|
+
) -> None:
|
|
226
|
+
self._state_file = state_file
|
|
227
|
+
self.api_key = (api_key or os.getenv("OWNAPI_API_KEY", "")).strip() or None
|
|
228
|
+
self._explicit_mode = mode.strip().lower() if isinstance(mode, str) and mode.strip() else None
|
|
229
|
+
|
|
230
|
+
if self.api_key:
|
|
231
|
+
tenant_record = get_tenant_info(self.api_key, state_file=self._state_file)
|
|
232
|
+
self.tenant_id = str(tenant_record.get("tenant_id", tenant_id or "default"))
|
|
233
|
+
self.plan = str(tenant_record.get("plan", "free"))
|
|
234
|
+
self.mode = str(self._explicit_mode or tenant_record.get("mode", "local")).lower()
|
|
235
|
+
else:
|
|
236
|
+
resolved_tenant = (tenant_id or "default").strip() or "default"
|
|
237
|
+
tenant_record = get_or_create_tenant(resolved_tenant, state_file=self._state_file)
|
|
238
|
+
self.tenant_id = str(tenant_record.get("tenant_id", resolved_tenant))
|
|
239
|
+
self.api_key = str(tenant_record.get("api_key", "")) or None
|
|
240
|
+
self.plan = str(tenant_record.get("plan", "free"))
|
|
241
|
+
self.mode = str(self._explicit_mode or tenant_record.get("mode", "local")).lower()
|
|
242
|
+
|
|
243
|
+
if self.mode not in ("local", "cloud"):
|
|
244
|
+
self.mode = "local"
|
|
245
|
+
|
|
246
|
+
self.cloud_cdp_url = cloud_cdp_url or os.getenv("OWNAPI_CLOUD_CDP_URL", "").strip() or None
|
|
247
|
+
self.non_interactive = bool(
|
|
248
|
+
non_interactive
|
|
249
|
+
or os.getenv("OWNAPI_NON_INTERACTIVE", "").strip().lower() in ("1", "true", "yes")
|
|
250
|
+
)
|
|
251
|
+
self.registry_root = pathlib.Path(registry_root)
|
|
252
|
+
self.token_store = TokenStore()
|
|
253
|
+
self.consent_manager = ConsentManager()
|
|
254
|
+
self.hitl_queue = HITLQueueManager()
|
|
255
|
+
self.auto_repair = AutoRepairEngine(
|
|
256
|
+
registry_root=self.registry_root,
|
|
257
|
+
tenant_id=self.tenant_id,
|
|
258
|
+
mode=self.mode,
|
|
259
|
+
)
|
|
260
|
+
self._agent = None
|
|
261
|
+
self._service_proxies: dict[str, ServiceNamespaceProxy] = {}
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def credits(self) -> int:
|
|
265
|
+
"""Kullanıcının güncel kalan kredi bakiyesini döndürür."""
|
|
266
|
+
info = get_tenant_info(self.api_key or self.tenant_id, state_file=self._state_file)
|
|
267
|
+
return int(info.get("credits", 0))
|
|
268
|
+
|
|
269
|
+
def status(self) -> dict[str, Any]:
|
|
270
|
+
"""Kullanıcının paket, kalan kredi, çalışma modu ve anahtar durumunu döndürür."""
|
|
271
|
+
return get_tenant_info(self.api_key or self.tenant_id, state_file=self._state_file)
|
|
272
|
+
|
|
273
|
+
def __getattr__(self, name: str) -> ServiceNamespaceProxy:
|
|
274
|
+
if name.startswith("_"):
|
|
275
|
+
raise AttributeError(name)
|
|
276
|
+
clean_name = name.strip().lower()
|
|
277
|
+
if clean_name not in self._service_proxies:
|
|
278
|
+
client_file = self.registry_root / clean_name / "client.py"
|
|
279
|
+
if not client_file.exists():
|
|
280
|
+
raise AttributeError(f"OwnAPI üzerinde '{name}' adında bir servis veya öznitelik bulunamadı.")
|
|
281
|
+
self._service_proxies[clean_name] = ServiceNamespaceProxy(
|
|
282
|
+
service_name=clean_name,
|
|
283
|
+
owner=self,
|
|
284
|
+
default_tenant_id=self.tenant_id,
|
|
285
|
+
default_mode=self.mode,
|
|
286
|
+
registry_root=self.registry_root,
|
|
287
|
+
state_file=self._state_file,
|
|
288
|
+
)
|
|
289
|
+
return self._service_proxies[clean_name]
|
|
290
|
+
|
|
291
|
+
def list_services(self) -> list[dict[str, Any]]:
|
|
292
|
+
"""Kayıtlı tüm servislerin şemalarını, fonksiyon adlarını ve parametrelerini listeler."""
|
|
293
|
+
tools = load_registry_tools(self.registry_root)
|
|
294
|
+
result: list[dict[str, Any]] = []
|
|
295
|
+
for schema, _ in tools:
|
|
296
|
+
result.append({
|
|
297
|
+
"service_name": schema.service_name,
|
|
298
|
+
"function_name": schema.function_name,
|
|
299
|
+
"goal": schema.goal,
|
|
300
|
+
"method": schema.method,
|
|
301
|
+
"endpoint_url": schema.endpoint_url,
|
|
302
|
+
"explanation": schema.explanation,
|
|
303
|
+
"parameters": [
|
|
304
|
+
{
|
|
305
|
+
"name": p.name,
|
|
306
|
+
"type": p.param_type,
|
|
307
|
+
"default": p.default_value,
|
|
308
|
+
"description": p.description,
|
|
309
|
+
"location": p.location,
|
|
310
|
+
}
|
|
311
|
+
for p in schema.dynamic_params
|
|
312
|
+
],
|
|
313
|
+
})
|
|
314
|
+
return result
|
|
315
|
+
|
|
316
|
+
def call(
|
|
317
|
+
self,
|
|
318
|
+
service_name: str,
|
|
319
|
+
mode: str | None = None,
|
|
320
|
+
non_interactive: bool | None = None,
|
|
321
|
+
_consume_credit: bool = True,
|
|
322
|
+
**kwargs: Any,
|
|
323
|
+
) -> Any:
|
|
324
|
+
"""
|
|
325
|
+
Belirtilen servisi API anahtarı / kredi kontrolü, ToS delegasyon onayı ve
|
|
326
|
+
aktif çalışma modu ('local' veya 'cloud') ile çağırır.
|
|
327
|
+
"""
|
|
328
|
+
tools = load_registry_tools(self.registry_root)
|
|
329
|
+
target_fn = None
|
|
330
|
+
target_schema = None
|
|
331
|
+
|
|
332
|
+
clean_req = service_name.strip().lower()
|
|
333
|
+
for schema, fn in tools:
|
|
334
|
+
if schema.service_name.lower() == clean_req or schema.function_name.lower() == clean_req:
|
|
335
|
+
target_fn = fn
|
|
336
|
+
target_schema = schema
|
|
337
|
+
break
|
|
338
|
+
|
|
339
|
+
if target_fn is None or target_schema is None:
|
|
340
|
+
available = [s.service_name for s, _ in tools]
|
|
341
|
+
raise ValueError(f"Servis '{service_name}' bulunamadı! Mevcut servisler: {available}")
|
|
342
|
+
|
|
343
|
+
# Kredi düşümü ve mod çözümlemesi
|
|
344
|
+
auth_id = self.api_key or self.tenant_id
|
|
345
|
+
info = get_tenant_info(auth_id, state_file=self._state_file)
|
|
346
|
+
if _consume_credit:
|
|
347
|
+
consume_credit(
|
|
348
|
+
auth_id,
|
|
349
|
+
amount=1,
|
|
350
|
+
state_file=self._state_file,
|
|
351
|
+
service=target_schema.service_name,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
active_mode = (mode or self._explicit_mode or info.get("mode") or self.mode or "local").strip().lower()
|
|
355
|
+
if active_mode not in ("local", "cloud"):
|
|
356
|
+
active_mode = "local"
|
|
357
|
+
active_ni = self.non_interactive if non_interactive is None else bool(non_interactive)
|
|
358
|
+
|
|
359
|
+
self.consent_manager.ensure_consent(
|
|
360
|
+
tenant_id=self.tenant_id,
|
|
361
|
+
service=target_schema.service_name,
|
|
362
|
+
action="sdk_call",
|
|
363
|
+
mode=active_mode,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
sig = inspect.signature(target_fn)
|
|
367
|
+
call_args = dict(kwargs)
|
|
368
|
+
|
|
369
|
+
if "tenant_id" in sig.parameters and "tenant_id" not in call_args:
|
|
370
|
+
call_args["tenant_id"] = self.tenant_id
|
|
371
|
+
if "mode" in sig.parameters and "mode" not in call_args:
|
|
372
|
+
call_args["mode"] = active_mode
|
|
373
|
+
|
|
374
|
+
prev_ni = os.environ.get("OWNAPI_NON_INTERACTIVE")
|
|
375
|
+
if active_ni:
|
|
376
|
+
os.environ["OWNAPI_NON_INTERACTIVE"] = "1"
|
|
377
|
+
try:
|
|
378
|
+
return target_fn(**call_args)
|
|
379
|
+
finally:
|
|
380
|
+
if active_ni:
|
|
381
|
+
if prev_ni is None:
|
|
382
|
+
os.environ.pop("OWNAPI_NON_INTERACTIVE", None)
|
|
383
|
+
else:
|
|
384
|
+
os.environ["OWNAPI_NON_INTERACTIVE"] = prev_ni
|
|
385
|
+
|
|
386
|
+
def validate_all(self, runs: int = 1, auto_heal: bool = True, services: list[str] | None = None) -> dict[str, Any]:
|
|
387
|
+
return self.auto_repair.validate_all_services(runs=runs, auto_heal=auto_heal, services=services)
|
|
388
|
+
|
|
389
|
+
def list_hitl_queue(self, status_filter: str | None = None) -> list[dict[str, Any]]:
|
|
390
|
+
return self.hitl_queue.list_tasks(tenant_id=self.tenant_id, status_filter=status_filter)
|
|
391
|
+
|
|
392
|
+
def resume_hitl_task(self, task_id: str, otp_code: str | None = None) -> dict[str, Any]:
|
|
393
|
+
return self.hitl_queue.resume_task(task_id=task_id, tenant_id=self.tenant_id, otp_code=otp_code)
|
|
394
|
+
|
|
395
|
+
def onboard(
|
|
396
|
+
self,
|
|
397
|
+
service_name: str,
|
|
398
|
+
start_url: str,
|
|
399
|
+
description: str = "",
|
|
400
|
+
headless: bool = False,
|
|
401
|
+
mode: str | None = None,
|
|
402
|
+
auto_validate: bool = True,
|
|
403
|
+
validation_runs: int = 3,
|
|
404
|
+
interactive_tos: bool = False,
|
|
405
|
+
) -> dict[str, Any]:
|
|
406
|
+
active_mode = (mode or self.mode or "local").strip().lower()
|
|
407
|
+
return onboard_new_site(
|
|
408
|
+
service_name=service_name,
|
|
409
|
+
start_url=start_url,
|
|
410
|
+
description=description,
|
|
411
|
+
headless=headless,
|
|
412
|
+
registry_root=self.registry_root,
|
|
413
|
+
tenant_id=self.tenant_id,
|
|
414
|
+
mode=active_mode,
|
|
415
|
+
auto_validate=auto_validate,
|
|
416
|
+
validation_runs=validation_runs,
|
|
417
|
+
interactive_tos=interactive_tos,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
def ask(self, prompt: str, _consume_credit: bool = True) -> str:
|
|
421
|
+
from agent_demo import ShadowAgent
|
|
422
|
+
|
|
423
|
+
auth_id = self.api_key or self.tenant_id
|
|
424
|
+
info = get_tenant_info(auth_id, state_file=self._state_file)
|
|
425
|
+
if _consume_credit:
|
|
426
|
+
consume_credit(auth_id, amount=1, state_file=self._state_file)
|
|
427
|
+
self.mode = str(self._explicit_mode or info.get("mode") or self.mode or "local").lower()
|
|
428
|
+
|
|
429
|
+
if self._agent is None:
|
|
430
|
+
self._agent = ShadowAgent(registry_root=self.registry_root)
|
|
431
|
+
return self._agent.ask(prompt)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
# Geriye dönük uyumluluk takma adları
|
|
435
|
+
OwnAPIClient = OwnAPI
|
|
436
|
+
ShadowClient = OwnAPI
|