Coverage for agentos/marketplace/__init__.py: 0%

386 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-07-02 09:59 +0800

1""" 

2AgentOS Marketplace — Agent template registry and discovery hub. 

3 

4v1.14.4: Central marketplace for discovering, publishing, and installing 

5 agent templates, workflows, and plugins. 

6 

7Key features: 

8- Template registry with semantic search 

9- Versioned agent templates with dependency resolution 

10- Public + private registries 

11- One-click install from marketplace 

12- Agent ratings, reviews, and usage stats 

13- Template validation and compatibility checking 

14- CLI and programmatic API 

15""" 

16 

17import asyncio 

18import hashlib 

19import json 

20import logging 

21import os 

22import shutil 

23import tempfile 

24import time 

25from abc import ABC, abstractmethod 

26from dataclasses import dataclass, field 

27from enum import Enum, auto 

28from pathlib import Path 

29from typing import Any, AsyncIterator, Callable, Dict, List, Optional, Set, Tuple, Union 

30from urllib.parse import urlparse 

31 

32logger = logging.getLogger(__name__) 

33 

34 

35# --------------------------------------------------------------------------- 

36# Data types 

37# --------------------------------------------------------------------------- 

38 

39class TemplateCategory(Enum): 

40 CHAT = "chat" 

41 CODING = "coding" 

42 ANALYSIS = "analysis" 

43 AUTOMATION = "automation" 

44 RESEARCH = "research" 

45 CREATIVE = "creative" 

46 ENTERPRISE = "enterprise" 

47 UTILITY = "utility" 

48 OTHER = "other" 

49 

50 

51class TemplateStatus(Enum): 

52 DRAFT = "draft" 

53 PUBLISHED = "published" 

54 DEPRECATED = "deprecated" 

55 ARCHIVED = "archived" 

56 UNDER_REVIEW = "under_review" 

57 

58 

59@dataclass 

60class TemplateDependency: 

61 """A dependency required by a template.""" 

62 name: str 

63 version_spec: str = "*" # PEP 440 version specifier 

64 optional: bool = False 

65 description: str = "" 

66 

67 

68@dataclass 

69class TemplateVersion: 

70 """A specific version of a template.""" 

71 version: str # SemVer 

72 changelog: str = "" 

73 min_agentos_version: str = "1.0.0" 

74 files: Dict[str, str] = field(default_factory=dict) # path → content 

75 dependencies: List[TemplateDependency] = field(default_factory=list) 

76 metadata: Dict[str, Any] = field(default_factory=dict) 

77 published_at: float = 0.0 

78 download_count: int = 0 

79 

80 

81@dataclass 

82class TemplateReview: 

83 """User review of a template.""" 

84 user_id: str 

85 rating: float # 1.0 - 5.0 

86 comment: str = "" 

87 timestamp: float = field(default_factory=time.time) 

88 helpful_count: int = 0 

89 

90 

91@dataclass 

92class AgentTemplate: 

93 """An agent template in the marketplace.""" 

94 # Identity 

95 id: str 

96 name: str 

97 version: str 

98 author: str 

99 description: str = "" 

100 category: TemplateCategory = TemplateCategory.OTHER 

101 tags: List[str] = field(default_factory=list) 

102 icon_url: str = "" 

103 

104 # Status 

105 status: TemplateStatus = TemplateStatus.PUBLISHED 

106 

107 # Content 

108 versions: List[TemplateVersion] = field(default_factory=list) 

109 readme: str = "" 

110 license: str = "MIT" 

111 

112 # Engagement 

113 stars: int = 0 

114 downloads: int = 0 

115 reviews: List[TemplateReview] = field(default_factory=list) 

116 

117 # Compatibility 

118 compatible_agentos_versions: str = ">=1.0.0" 

119 requires: List[TemplateDependency] = field(default_factory=list) 

120 

121 # Metadata 

122 created_at: float = field(default_factory=time.time) 

123 updated_at: float = field(default_factory=time.time) 

124 source_url: str = "" 

125 documentation_url: str = "" 

126 metadata: Dict[str, Any] = field(default_factory=dict) 

127 

128 @property 

129 def rating(self) -> float: 

130 """Average rating.""" 

131 if not self.reviews: 

132 return 0.0 

133 return sum(r.rating for r in self.reviews) / len(self.reviews) 

134 

135 @property 

136 def latest_version(self) -> Optional[TemplateVersion]: 

137 """Get the latest published version.""" 

138 published = [v for v in self.versions if v.published_at > 0] 

139 if not published: 

140 return None 

141 return max(published, key=lambda v: v.published_at) 

142 

143 

144@dataclass 

145class MarketSearchQuery: 

146 """Search query for the marketplace.""" 

147 keywords: str = "" 

148 category: Optional[TemplateCategory] = None 

149 tags: List[str] = field(default_factory=list) 

150 min_rating: float = 0.0 

151 min_stars: int = 0 

152 author: Optional[str] = None 

153 sort_by: str = "relevance" # relevance, downloads, rating, stars, updated 

154 sort_order: str = "desc" 

155 limit: int = 20 

156 offset: int = 0 

157 

158 

159@dataclass 

160class MarketSearchResult: 

161 """Search result from the marketplace.""" 

162 template: AgentTemplate 

163 score: float = 0.0 

164 matched_tags: List[str] = field(default_factory=list) 

165 

166 

167# --------------------------------------------------------------------------- 

168# Registry backends 

169# --------------------------------------------------------------------------- 

170 

171class MarketRegistryBackend(ABC): 

172 """Abstract backend for template storage and retrieval.""" 

173 

174 @abstractmethod 

175 async def list_templates( 

176 self, query: Optional[MarketSearchQuery] = None 

177 ) -> List[MarketSearchResult]: 

178 ... 

179 

180 @abstractmethod 

181 async def get_template(self, template_id: str) -> Optional[AgentTemplate]: 

182 ... 

183 

184 @abstractmethod 

185 async def publish_template(self, template: AgentTemplate) -> bool: 

186 ... 

187 

188 @abstractmethod 

189 async def unpublish_template(self, template_id: str) -> bool: 

190 ... 

191 

192 @abstractmethod 

193 async def add_review(self, template_id: str, review: TemplateReview) -> bool: 

194 ... 

195 

196 @abstractmethod 

197 async def get_stats(self) -> Dict[str, Any]: 

198 ... 

199 

200 

201class InMemoryMarketBackend(MarketRegistryBackend): 

202 """In-memory registry for development and testing.""" 

203 

204 def __init__(self): 

205 self._templates: Dict[str, AgentTemplate] = {} 

206 

207 async def list_templates( 

208 self, query: Optional[MarketSearchQuery] = None 

209 ) -> List[MarketSearchResult]: 

210 results = [] 

211 for tpl in self._templates.values(): 

212 if tpl.status != TemplateStatus.PUBLISHED: 

213 continue 

214 

215 score = 0.0 

216 matched_tags = [] 

217 

218 if query: 

219 # Keyword search 

220 if query.keywords: 

221 kw_lower = query.keywords.lower() 

222 text = f"{tpl.name} {tpl.description} {' '.join(tpl.tags)}".lower() 

223 if kw_lower in text: 

224 score += 10.0 

225 

226 # Category filter 

227 if query.category and tpl.category != query.category: 

228 continue 

229 

230 # Tag filter 

231 if query.tags: 

232 matched_tags = [t for t in query.tags if t in tpl.tags] 

233 if not matched_tags: 

234 continue 

235 score += len(matched_tags) * 2.0 

236 

237 # Rating filter 

238 if query.min_rating > 0 and tpl.rating < query.min_rating: 

239 continue 

240 

241 # Stars filter 

242 if query.min_stars > 0 and tpl.stars < query.min_stars: 

243 continue 

244 

245 # Author filter 

246 if query.author and tpl.author != query.author: 

247 continue 

248 

249 results.append(MarketSearchResult( 

250 template=tpl, 

251 score=score, 

252 matched_tags=matched_tags, 

253 )) 

254 

255 # Sort 

256 if query: 

257 sort_key = query.sort_by 

258 reverse = query.sort_order == "desc" 

259 if sort_key == "downloads": 

260 results.sort(key=lambda r: r.template.downloads, reverse=reverse) 

261 elif sort_key == "rating": 

262 results.sort(key=lambda r: r.template.rating, reverse=reverse) 

263 elif sort_key == "stars": 

264 results.sort(key=lambda r: r.template.stars, reverse=reverse) 

265 elif sort_key == "updated": 

266 results.sort(key=lambda r: r.template.updated_at, reverse=reverse) 

267 else: # relevance 

268 results.sort(key=lambda r: r.score, reverse=reverse) 

269 

270 # Paginate 

271 results = results[query.offset:query.offset + query.limit] 

272 

273 return results 

274 

275 async def get_template(self, template_id: str) -> Optional[AgentTemplate]: 

276 return self._templates.get(template_id) 

277 

278 async def publish_template(self, template: AgentTemplate) -> bool: 

279 template.updated_at = time.time() 

280 self._templates[template.id] = template 

281 return True 

282 

283 async def unpublish_template(self, template_id: str) -> bool: 

284 if template_id in self._templates: 

285 self._templates[template_id].status = TemplateStatus.ARCHIVED 

286 return True 

287 return False 

288 

289 async def add_review(self, template_id: str, review: TemplateReview) -> bool: 

290 tpl = self._templates.get(template_id) 

291 if not tpl: 

292 return False 

293 tpl.reviews.append(review) 

294 return True 

295 

296 async def get_stats(self) -> Dict[str, Any]: 

297 total = len(self._templates) 

298 by_category = {} 

299 for tpl in self._templates.values(): 

300 cat = tpl.category.value 

301 by_category[cat] = by_category.get(cat, 0) + 1 

302 return { 

303 "total_templates": total, 

304 "total_downloads": sum(t.downloads for t in self._templates.values()), 

305 "by_category": by_category, 

306 } 

307 

308 

309class FileMarketBackend(MarketRegistryBackend): 

310 """JSON-file-based registry for local/CI usage.""" 

311 

312 def __init__(self, storage_dir: Union[str, Path]): 

313 self._dir = Path(storage_dir) 

314 self._dir.mkdir(parents=True, exist_ok=True) 

315 self._index_file = self._dir / "index.json" 

316 self._templates: Dict[str, AgentTemplate] = {} 

317 self._load() 

318 

319 def _load(self) -> None: 

320 if self._index_file.exists(): 

321 with open(self._index_file, "r") as f: 

322 data = json.load(f) 

323 for raw in data.get("templates", []): 

324 tpl = self._dict_to_template(raw) 

325 self._templates[tpl.id] = tpl 

326 

327 def _save(self) -> None: 

328 data = { 

329 "updated_at": time.time(), 

330 "templates": [self._template_to_dict(t) for t in self._templates.values()], 

331 } 

332 with open(self._index_file, "w") as f: 

333 json.dump(data, f, indent=2, default=str) 

334 

335 def _template_to_dict(self, tpl: AgentTemplate) -> Dict[str, Any]: 

336 return { 

337 "id": tpl.id, 

338 "name": tpl.name, 

339 "version": tpl.version, 

340 "author": tpl.author, 

341 "description": tpl.description, 

342 "category": tpl.category.value, 

343 "tags": tpl.tags, 

344 "status": tpl.status.value, 

345 "stars": tpl.stars, 

346 "downloads": tpl.downloads, 

347 "rating": tpl.rating, 

348 "review_count": len(tpl.reviews), 

349 "compatible_agentos_versions": tpl.compatible_agentos_versions, 

350 "created_at": tpl.created_at, 

351 "updated_at": tpl.updated_at, 

352 } 

353 

354 def _dict_to_template(self, d: Dict[str, Any]) -> AgentTemplate: 

355 return AgentTemplate( 

356 id=d["id"], 

357 name=d["name"], 

358 version=d.get("version", "1.0.0"), 

359 author=d["author"], 

360 description=d.get("description", ""), 

361 category=TemplateCategory(d.get("category", "other")), 

362 tags=d.get("tags", []), 

363 status=TemplateStatus(d.get("status", "published")), 

364 stars=d.get("stars", 0), 

365 downloads=d.get("downloads", 0), 

366 compatible_agentos_versions=d.get("compatible_agentos_versions", ">=1.0.0"), 

367 created_at=d.get("created_at", 0), 

368 updated_at=d.get("updated_at", 0), 

369 ) 

370 

371 # Delegate to in-memory backend 

372 async def list_templates(self, query=None): 

373 backend = InMemoryMarketBackend() 

374 backend._templates = dict(self._templates) 

375 return await backend.list_templates(query) 

376 

377 async def get_template(self, template_id): 

378 return self._templates.get(template_id) 

379 

380 async def publish_template(self, template): 

381 tpl = AgentTemplate(**{ 

382 k: v for k, v in template.__dict__.items() 

383 if k in AgentTemplate.__dataclass_fields__ 

384 }) 

385 template.updated_at = time.time() 

386 self._templates[template.id] = template 

387 self._save() 

388 return True 

389 

390 async def unpublish_template(self, template_id): 

391 if template_id in self._templates: 

392 self._templates[template_id].status = TemplateStatus.ARCHIVED 

393 self._save() 

394 return True 

395 return False 

396 

397 async def add_review(self, template_id, review): 

398 tpl = self._templates.get(template_id) 

399 if not tpl: 

400 return False 

401 tpl.reviews.append(review) 

402 self._save() 

403 return True 

404 

405 async def get_stats(self): 

406 backend = InMemoryMarketBackend() 

407 backend._templates = dict(self._templates) 

408 return await backend.get_stats() 

409 

410 

411# --------------------------------------------------------------------------- 

412# Remote registry client 

413# --------------------------------------------------------------------------- 

414 

415class RemoteMarketClient: 

416 """HTTP client for remote marketplace registries.""" 

417 

418 def __init__(self, base_url: str, api_key: Optional[str] = None): 

419 self.base_url = base_url.rstrip("/") 

420 self.api_key = api_key 

421 

422 async def search(self, query: MarketSearchQuery) -> List[MarketSearchResult]: 

423 """Search the remote marketplace.""" 

424 import urllib.request 

425 import urllib.parse 

426 

427 params = {} 

428 if query.keywords: 

429 params["q"] = query.keywords 

430 if query.category: 

431 params["category"] = query.category.value 

432 if query.tags: 

433 params["tags"] = ",".join(query.tags) 

434 if query.limit: 

435 params["limit"] = str(query.limit) 

436 

437 url = f"{self.base_url}/api/v1/templates" 

438 if params: 

439 url += "?" + urllib.parse.urlencode(params) 

440 

441 # Use asyncio-compatible HTTP 

442 import aiohttp 

443 async with aiohttp.ClientSession() as session: 

444 headers = {} 

445 if self.api_key: 

446 headers["Authorization"] = f"Bearer {self.api_key}" 

447 async with session.get(url, headers=headers) as resp: 

448 data = await resp.json() 

449 return [ 

450 MarketSearchResult( 

451 template=AgentTemplate(**item["template"]), 

452 score=item.get("score", 0), 

453 ) 

454 for item in data.get("results", []) 

455 ] 

456 

457 async def get_template(self, template_id: str) -> Optional[AgentTemplate]: 

458 """Fetch a template from the remote registry.""" 

459 import aiohttp 

460 async with aiohttp.ClientSession() as session: 

461 headers = {} 

462 if self.api_key: 

463 headers["Authorization"] = f"Bearer {self.api_key}" 

464 async with session.get( 

465 f"{self.base_url}/api/v1/templates/{template_id}", 

466 headers=headers, 

467 ) as resp: 

468 if resp.status == 404: 

469 return None 

470 data = await resp.json() 

471 return AgentTemplate(**data) 

472 

473 async def download_template( 

474 self, template_id: str, target_dir: Union[str, Path] 

475 ) -> bool: 

476 """Download and extract a template to a local directory.""" 

477 import aiohttp 

478 target = Path(target_dir) 

479 target.mkdir(parents=True, exist_ok=True) 

480 

481 async with aiohttp.ClientSession() as session: 

482 headers = {} 

483 if self.api_key: 

484 headers["Authorization"] = f"Bearer {self.api_key}" 

485 async with session.get( 

486 f"{self.base_url}/api/v1/templates/{template_id}/download", 

487 headers=headers, 

488 ) as resp: 

489 if resp.status != 200: 

490 return False 

491 

492 import tarfile 

493 import io 

494 data = await resp.read() 

495 with tarfile.open(fileobj=io.BytesIO(data)) as tar: 

496 tar.extractall(path=target) 

497 return True 

498 

499 

500# --------------------------------------------------------------------------- 

501# Marketplace Manager 

502# --------------------------------------------------------------------------- 

503 

504class MarketplaceManager: 

505 """Central marketplace management — search, install, publish.""" 

506 

507 def __init__( 

508 self, 

509 local_backend: Optional[MarketRegistryBackend] = None, 

510 remote_clients: Optional[List[RemoteMarketClient]] = None, 

511 install_dir: Union[str, Path] = "~/.agentos/templates", 

512 ): 

513 self.local = local_backend or InMemoryMarketBackend() 

514 self.remote_clients = remote_clients or [] 

515 self.install_dir = Path(install_dir).expanduser() 

516 self.install_dir.mkdir(parents=True, exist_ok=True) 

517 

518 async def search( 

519 self, query: MarketSearchQuery, include_remote: bool = True 

520 ) -> List[MarketSearchResult]: 

521 """Search local and remote registries.""" 

522 results = await self.local.list_templates(query) 

523 

524 if include_remote: 

525 for client in self.remote_clients: 

526 try: 

527 remote_results = await client.search(query) 

528 results.extend(remote_results) 

529 except Exception as e: 

530 logger.warning(f"Remote search failed: {e}") 

531 

532 # Deduplicate by template ID 

533 seen: Set[str] = set() 

534 deduped = [] 

535 for r in results: 

536 if r.template.id not in seen: 

537 seen.add(r.template.id) 

538 deduped.append(r) 

539 

540 return deduped 

541 

542 async def install(self, template_id: str, version: Optional[str] = None) -> Path: 

543 """Install a template from local or remote registry.""" 

544 # Check local first 

545 tpl = await self.local.get_template(template_id) 

546 

547 # Try remote 

548 if not tpl: 

549 for client in self.remote_clients: 

550 try: 

551 tpl = await client.get_template(template_id) 

552 if tpl: 

553 break 

554 except Exception: 

555 continue 

556 

557 if not tpl: 

558 raise ValueError(f"Template '{template_id}' not found in any registry") 

559 

560 # Install to local directory 

561 tpl_dir = self.install_dir / template_id 

562 if version: 

563 tpl_dir = tpl_dir / version 

564 

565 tpl_dir.mkdir(parents=True, exist_ok=True) 

566 

567 # Write template files 

568 latest = tpl.latest_version 

569 if latest: 

570 for filepath, content in latest.files.items(): 

571 full_path = tpl_dir / filepath 

572 full_path.parent.mkdir(parents=True, exist_ok=True) 

573 with open(full_path, "w") as f: 

574 f.write(content) 

575 

576 # Record installation 

577 tpl.downloads += 1 

578 tpl.updated_at = time.time() 

579 

580 return tpl_dir 

581 

582 async def publish( 

583 self, 

584 template: AgentTemplate, 

585 to_remote: bool = False, 

586 ) -> bool: 

587 """Publish a template to registries.""" 

588 # Always publish to local 

589 ok = await self.local.publish_template(template) 

590 if not ok: 

591 return False 

592 

593 # Optionally push to remote 

594 if to_remote: 

595 for client in self.remote_clients: 

596 try: 

597 # Remote publishing would use a POST endpoint 

598 pass 

599 except Exception as e: 

600 logger.error(f"Remote publish failed: {e}") 

601 

602 return True 

603 

604 async def get_stats(self) -> Dict[str, Any]: 

605 """Get marketplace statistics.""" 

606 return await self.local.get_stats() 

607 

608 async def get_featured(self, limit: int = 10) -> List[AgentTemplate]: 

609 """Get featured/popular templates.""" 

610 query = MarketSearchQuery(sort_by="downloads", limit=limit) 

611 results = await self.local.list_templates(query) 

612 return [r.template for r in results] 

613 

614 async def get_by_category( 

615 self, category: TemplateCategory, limit: int = 20 

616 ) -> List[AgentTemplate]: 

617 """Get templates by category.""" 

618 query = MarketSearchQuery(category=category, limit=limit) 

619 results = await self.local.list_templates(query) 

620 return [r.template for r in results] 

621 

622 

623# --------------------------------------------------------------------------- 

624# Template builder 

625# --------------------------------------------------------------------------- 

626 

627class TemplateBuilder: 

628 """Helper to build AgentTemplate objects programmatically.""" 

629 

630 def __init__(self, name: str, author: str, version: str = "1.0.0"): 

631 self._template = AgentTemplate( 

632 id=hashlib.sha256(f"{author}/{name}".encode()).hexdigest()[:16], 

633 name=name, 

634 version=version, 

635 author=author, 

636 ) 

637 

638 def description(self, text: str) -> "TemplateBuilder": 

639 self._template.description = text 

640 return self 

641 

642 def category(self, cat: TemplateCategory) -> "TemplateBuilder": 

643 self._template.category = cat 

644 return self 

645 

646 def tags(self, *tags: str) -> "TemplateBuilder": 

647 self._template.tags = list(tags) 

648 return self 

649 

650 def add_version( 

651 self, version: str, files: Dict[str, str], changelog: str = "" 

652 ) -> "TemplateBuilder": 

653 tv = TemplateVersion( 

654 version=version, 

655 changelog=changelog, 

656 files=files, 

657 published_at=time.time(), 

658 ) 

659 self._template.versions.append(tv) 

660 return self 

661 

662 def add_dependency( 

663 self, name: str, version_spec: str = "*", optional: bool = False 

664 ) -> "TemplateBuilder": 

665 self._template.requires.append( 

666 TemplateDependency(name=name, version_spec=version_spec, optional=optional) 

667 ) 

668 return self 

669 

670 def add_review(self, user_id: str, rating: float, comment: str = "") -> "TemplateBuilder": 

671 self._template.reviews.append( 

672 TemplateReview(user_id=user_id, rating=rating, comment=comment) 

673 ) 

674 return self 

675 

676 def build(self) -> AgentTemplate: 

677 if not self._template.description: 

678 raise ValueError("Template must have a description") 

679 return self._template 

680 

681 

682# --------------------------------------------------------------------------- 

683# Pre-seeded templates 

684# --------------------------------------------------------------------------- 

685 

686def seed_default_templates(manager: MarketplaceManager) -> None: 

687 """Seed the marketplace with default templates.""" 

688 templates = [ 

689 TemplateBuilder("Conversational Agent", "AgentOS Team") 

690 .description("General-purpose conversational agent with memory and tool use") 

691 .category(TemplateCategory.CHAT) 

692 .tags("chat", "conversation", "memory") 

693 .add_version("1.0.0", { 

694 "agent.yaml": "name: conversational-agent\ntype: chat\nmemory: enabled", 

695 "main.py": "from agentos import Agent\n\nagent = Agent(...)", 

696 }) 

697 .build(), 

698 

699 TemplateBuilder("Code Review Assistant", "AgentOS Team") 

700 .description("AI-powered code reviewer with PR integration") 

701 .category(TemplateCategory.CODING) 

702 .tags("code", "review", "github", "pr") 

703 .add_version("1.0.0", { 

704 "agent.yaml": "name: code-reviewer\ntype: coding\n", 

705 "review.py": "async def review_pr(pr_url): ...", 

706 }) 

707 .build(), 

708 

709 TemplateBuilder("Research Analyst", "AgentOS Team") 

710 .description("Multi-source research agent with deep analysis capabilities") 

711 .category(TemplateCategory.RESEARCH) 

712 .tags("research", "analysis", "web") 

713 .add_version("1.0.0", { 

714 "agent.yaml": "name: research-analyst\ntype: research\n", 

715 "analyst.py": "async def deep_research(topic): ...", 

716 }) 

717 .build(), 

718 

719 TemplateBuilder("Data Pipeline Agent", "AgentOS Team") 

720 .description("Automated ETL and data processing pipeline") 

721 .category(TemplateCategory.AUTOMATION) 

722 .tags("etl", "data", "pipeline", "automation") 

723 .add_version("1.0.0", { 

724 "agent.yaml": "name: data-pipeline\ntype: automation\n", 

725 "pipeline.py": "async def run_pipeline(config): ...", 

726 }) 

727 .build(), 

728 

729 TemplateBuilder("Document Writer", "AgentOS Team") 

730 .description("Professional document generation from outlines or templates") 

731 .category(TemplateCategory.CREATIVE) 

732 .tags("writing", "document", "report") 

733 .add_version("1.0.0", { 

734 "agent.yaml": "name: doc-writer\ntype: creative\n", 

735 "writer.py": "async def generate_doc(outline): ...", 

736 }) 

737 .build(), 

738 ] 

739 

740 async def _seed(): 

741 for tpl in templates: 

742 await manager.local.publish_template(tpl) 

743 

744 try: 

745 asyncio.get_event_loop().run_until_complete(_seed()) 

746 except RuntimeError: 

747 asyncio.run(_seed()) 

748 

749 

750# --------------------------------------------------------------------------- 

751# Export 

752# --------------------------------------------------------------------------- 

753 

754__all__ = [ 

755 # Enums 

756 "TemplateCategory", 

757 "TemplateStatus", 

758 # Data types 

759 "TemplateDependency", 

760 "TemplateVersion", 

761 "TemplateReview", 

762 "AgentTemplate", 

763 "MarketSearchQuery", 

764 "MarketSearchResult", 

765 # Backends 

766 "MarketRegistryBackend", 

767 "InMemoryMarketBackend", 

768 "FileMarketBackend", 

769 "RemoteMarketClient", 

770 # Manager 

771 "MarketplaceManager", 

772 "TemplateBuilder", 

773 "seed_default_templates", 

774]