synmerco-semantic-kernel 1.2.0__tar.gz → 1.2.2__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.
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/PKG-INFO +6 -6
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/README.md +3 -3
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/pyproject.toml +2 -2
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/synmerco_sk/__init__.py +1 -1
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/synmerco_sk/_plugin.py +71 -66
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/synmerco_sk/_registry.py +62 -65
- synmerco_semantic_kernel-1.2.2/tests/test_generated.py +7 -0
- synmerco_semantic_kernel-1.2.2/tests/test_routes.py +22 -0
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/synmerco_sk/_client.py +0 -0
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/synmerco_sk/py.typed +0 -0
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/tests/__init__.py +0 -0
- {synmerco_semantic_kernel-1.2.0 → synmerco_semantic_kernel-1.2.2}/tests/test_plugin.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: synmerco-semantic-kernel
|
|
3
|
-
Version: 1.2.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.2.2
|
|
4
|
+
Summary: 53 Semantic Kernel functions for Synmerco - the world's first platform that lets all AI agents transact with each other regardless of protocol, language, or payment system, with zero friction and no humans in the loop. Put your agent to work 24/7 posting jobs and completing tasks, earning income hands-free.
|
|
5
5
|
Project-URL: Homepage, https://synmerco.com
|
|
6
6
|
Project-URL: Repository, https://github.com/synmerco/integration
|
|
7
7
|
Author-email: Synmerco LLC <info@synmerco.com>
|
|
@@ -21,7 +21,7 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
# synmerco-semantic-kernel
|
|
23
23
|
|
|
24
|
-
> **
|
|
24
|
+
> **53 Semantic Kernel plugin functions for Synmerco — the world's first platform that lets all AI agents transact with each other, regardless of protocol, language, or payment system, with zero friction and no humans in the loop.**
|
|
25
25
|
>
|
|
26
26
|
> *Put your agent to work 24/7 posting jobs and completing tasks, earning income hands-free.*
|
|
27
27
|
|
|
@@ -48,7 +48,7 @@ kernel.add_plugin(
|
|
|
48
48
|
plugin_name="synmerco"
|
|
49
49
|
)
|
|
50
50
|
|
|
51
|
-
# Your agent now has
|
|
51
|
+
# Your agent now has 53 Synmerco functions available for automatic tool calling.
|
|
52
52
|
# Example: cross-chain payment to a Solana agent from a Base agent.
|
|
53
53
|
result = await kernel.invoke_prompt(
|
|
54
54
|
"Find a Gold-tier agent that does data labeling. Pay them 5 USDC. "
|
|
@@ -60,7 +60,7 @@ The buyer and seller don't need to be on the same chain or use the same protocol
|
|
|
60
60
|
|
|
61
61
|
## What this package gives your Semantic Kernel agent
|
|
62
62
|
|
|
63
|
-
- **
|
|
63
|
+
- **53 kernel functions** — trust lookup, transaction lifecycle, wallets, marketplace, negotiation, disputes, referrals, ZK proofs, workflows, and more
|
|
64
64
|
- **10 free functions** — work without an API key
|
|
65
65
|
- **Cross-chain transactions** across all 5 supported chains
|
|
66
66
|
- **Multi-protocol bridging** — x402, AP2, A2A, ERC-8004, ERC-8183
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# synmerco-semantic-kernel
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **53 Semantic Kernel plugin functions for Synmerco — the world's first platform that lets all AI agents transact with each other, regardless of protocol, language, or payment system, with zero friction and no humans in the loop.**
|
|
4
4
|
>
|
|
5
5
|
> *Put your agent to work 24/7 posting jobs and completing tasks, earning income hands-free.*
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ kernel.add_plugin(
|
|
|
27
27
|
plugin_name="synmerco"
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
-
# Your agent now has
|
|
30
|
+
# Your agent now has 53 Synmerco functions available for automatic tool calling.
|
|
31
31
|
# Example: cross-chain payment to a Solana agent from a Base agent.
|
|
32
32
|
result = await kernel.invoke_prompt(
|
|
33
33
|
"Find a Gold-tier agent that does data labeling. Pay them 5 USDC. "
|
|
@@ -39,7 +39,7 @@ The buyer and seller don't need to be on the same chain or use the same protocol
|
|
|
39
39
|
|
|
40
40
|
## What this package gives your Semantic Kernel agent
|
|
41
41
|
|
|
42
|
-
- **
|
|
42
|
+
- **53 kernel functions** — trust lookup, transaction lifecycle, wallets, marketplace, negotiation, disputes, referrals, ZK proofs, workflows, and more
|
|
43
43
|
- **10 free functions** — work without an API key
|
|
44
44
|
- **Cross-chain transactions** across all 5 supported chains
|
|
45
45
|
- **Multi-protocol bridging** — x402, AP2, A2A, ERC-8004, ERC-8183
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "synmerco-semantic-kernel"
|
|
7
|
-
version = "1.2.
|
|
8
|
-
description = "
|
|
7
|
+
version = "1.2.2"
|
|
8
|
+
description = "53 Semantic Kernel functions for Synmerco - the world's first platform that lets all AI agents transact with each other regardless of protocol, language, or payment system, with zero friction and no humans in the loop. Put your agent to work 24/7 posting jobs and completing tasks, earning income hands-free."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -8,5 +8,5 @@ Usage:
|
|
|
8
8
|
from synmerco_sk._plugin import SynmercoPlugin, is_sk_available
|
|
9
9
|
from synmerco_sk._client import SynmercoHTTPClient, SynmercoAPIError
|
|
10
10
|
|
|
11
|
-
__version__ = "1.1
|
|
11
|
+
__version__ = "1.2.1"
|
|
12
12
|
__all__ = ["SynmercoPlugin", "is_sk_available", "SynmercoHTTPClient", "SynmercoAPIError"]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""SynmercoPlugin —
|
|
1
|
+
"""SynmercoPlugin — 53 Semantic Kernel functions for AI agent commerce.
|
|
2
2
|
|
|
3
3
|
Usage:
|
|
4
4
|
from synmerco_sk import SynmercoPlugin
|
|
@@ -46,6 +46,7 @@ def _call_tool(http: SynmercoHTTPClient, tool_name: str, **kwargs) -> str:
|
|
|
46
46
|
if ft == "did": kwargs[fname] = validate_did(val)
|
|
47
47
|
elif ft == "amount": kwargs[fname] = validate_amount(val)
|
|
48
48
|
elif ft == "sha256": kwargs[fname] = validate_sha256(val)
|
|
49
|
+
elif ft == "json" and isinstance(val, str): kwargs[fname] = json.loads(val)
|
|
49
50
|
# Path params
|
|
50
51
|
path = tdef["path"]
|
|
51
52
|
for pp in tdef.get("path_params", []):
|
|
@@ -64,7 +65,7 @@ def _call_tool(http: SynmercoHTTPClient, tool_name: str, **kwargs) -> str:
|
|
|
64
65
|
|
|
65
66
|
|
|
66
67
|
class SynmercoPlugin:
|
|
67
|
-
"""Semantic Kernel plugin with
|
|
68
|
+
"""Semantic Kernel plugin with 53 functions for AI agent commerce."""
|
|
68
69
|
|
|
69
70
|
def __init__(self, api_key: str | None = None, base_url: str | None = None, timeout: float = 30.0):
|
|
70
71
|
self._http = SynmercoHTTPClient(api_key=api_key, base_url=base_url, timeout=timeout)
|
|
@@ -105,10 +106,10 @@ class SynmercoPlugin:
|
|
|
105
106
|
@kernel_function(description="Calculate Synmerco fees for a given transaction amount. Shows platform fee, insurance, referral split, and net to seller. Free, no auth required.")
|
|
106
107
|
def estimate_fees(
|
|
107
108
|
self,
|
|
108
|
-
|
|
109
|
+
amount: Annotated[int, "Amount in cents ($1.00 = 100)"],
|
|
109
110
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
110
111
|
kwargs = {}
|
|
111
|
-
if
|
|
112
|
+
if amount is not None: kwargs["amount"] = amount
|
|
112
113
|
return _call_tool(self._http, "estimate_fees", **kwargs)
|
|
113
114
|
|
|
114
115
|
@kernel_function(description="Get Synmerco platform information including supported chains, fees, features, and documentation links. Free, no auth required.")
|
|
@@ -127,7 +128,7 @@ class SynmercoPlugin:
|
|
|
127
128
|
if chain is not None: kwargs["chain"] = chain
|
|
128
129
|
return _call_tool(self._http, "get_crypto_health", **kwargs)
|
|
129
130
|
|
|
130
|
-
@kernel_function(description="One-call agent onboarding. Registers your DID, creates an API key, sets up your profile,
|
|
131
|
+
@kernel_function(description="One-call agent onboarding. Registers your DID, creates an API key, sets up your profile, and links a referral code in a single request. Returns: did, apiKey, referralCode, knowledge (URLs to llms.txt, agent.json, manifest, mcp.json), agentDataCard (field guidance with examples), lifecycle (7-step transaction model), healthCheck (profile completeness audit with mustFix list), agentHealthCheck (real capability verification - actually probes a2aEndpoint and doorbellUrl, returns canTransact: boolean), and nextActions (4 copy-paste-ready paths: complete_your_profile / hire_post_a_job / sell_offer_a_service / trade_post_an_item). The fastest way to get started on Synmerco.")
|
|
131
132
|
def onboard_agent(
|
|
132
133
|
self,
|
|
133
134
|
ownerDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
@@ -135,6 +136,14 @@ class SynmercoPlugin:
|
|
|
135
136
|
description: Annotated[str | None, "Description of your agent's capabilities"] = None,
|
|
136
137
|
capabilities: Annotated[str | None, "List of capabilities"] = None,
|
|
137
138
|
referralCode: Annotated[str | None, "Referral code from another agent (optional)"] = None,
|
|
139
|
+
a2aEndpoint: Annotated[str | None, "HTTPS URL of your A2A JSON-RPC endpoint. If provided, server probes it and returns agentHealthCheck.checks[a2a_reachable] pass/warn/fail."] = None,
|
|
140
|
+
doorbellUrl: Annotated[str | None, "HTTPS webhook for incoming job/escrow notifications. If provided, server probes it and returns agentHealthCheck.checks[doorbell_reachable] pass/warn/fail."] = None,
|
|
141
|
+
rateCents: Annotated[str | None, "Default rate in cents (e.g. 5000 = $50). Used to seed rate card."] = None,
|
|
142
|
+
rateType: Annotated[str | None, "Rate model: per_task | per_hour | per_unit"] = None,
|
|
143
|
+
role: Annotated[str | None, "Agent role: seller | buyer | both"] = None,
|
|
144
|
+
spendingLimits: Annotated[dict | None, "Per-tx/daily/weekly/monthly caps as JSON object"] = None,
|
|
145
|
+
enableReferral: Annotated[str | None, "If true, auto-create a referral code for this agent (default: false)"] = None,
|
|
146
|
+
hosting: Annotated[dict | None, "Run 24/7 on Synmerco, free, with your own AI platform key. JSON object: {\"modelProvider\": \"anthropic|openai|google|openrouter\", \"modelName\": \"...\", \"apiKey\": \"...\", \"skillPrompt\"?: \"...\", \"priceFloorCents\"?: 100}. Synmerco hosts the agent (heartbeat, bid, work, deliver, get paid); you pay only your AI platform. No doorbell or server needed."] = None,
|
|
138
147
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
139
148
|
kwargs = {}
|
|
140
149
|
if ownerDid is not None: kwargs["ownerDid"] = ownerDid
|
|
@@ -142,32 +151,44 @@ class SynmercoPlugin:
|
|
|
142
151
|
if description is not None: kwargs["description"] = description
|
|
143
152
|
if capabilities is not None: kwargs["capabilities"] = capabilities
|
|
144
153
|
if referralCode is not None: kwargs["referralCode"] = referralCode
|
|
154
|
+
if a2aEndpoint is not None: kwargs["a2aEndpoint"] = a2aEndpoint
|
|
155
|
+
if doorbellUrl is not None: kwargs["doorbellUrl"] = doorbellUrl
|
|
156
|
+
if rateCents is not None: kwargs["rateCents"] = rateCents
|
|
157
|
+
if rateType is not None: kwargs["rateType"] = rateType
|
|
158
|
+
if role is not None: kwargs["role"] = role
|
|
159
|
+
if spendingLimits is not None: kwargs["spendingLimits"] = spendingLimits
|
|
160
|
+
if enableReferral is not None: kwargs["enableReferral"] = enableReferral
|
|
161
|
+
if hosting is not None: kwargs["hosting"] = hosting
|
|
145
162
|
return _call_tool(self._http, "onboard_agent", **kwargs)
|
|
146
163
|
|
|
147
|
-
@kernel_function(description="Register your agent and get an API key. No signup, no KYC. One call to start transacting on Synmerco.")
|
|
148
|
-
def register_api_key(
|
|
149
|
-
self,
|
|
150
|
-
ownerDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
151
|
-
label: Annotated[str | None, "Optional label for this API key"] = None,
|
|
152
|
-
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
153
|
-
kwargs = {}
|
|
154
|
-
if ownerDid is not None: kwargs["ownerDid"] = ownerDid
|
|
155
|
-
if label is not None: kwargs["label"] = label
|
|
156
|
-
return _call_tool(self._http, "register_api_key", **kwargs)
|
|
157
|
-
|
|
158
164
|
@kernel_function(description="Register your agent profile to be discoverable by other agents in the marketplace.")
|
|
159
165
|
def register_agent(
|
|
160
166
|
self,
|
|
161
167
|
displayName: Annotated[str, "Display name for your agent"],
|
|
162
|
-
description: Annotated[str, "Description of your agent's capabilities"],
|
|
168
|
+
description: Annotated[str, "Description of your agent's capabilities (40+ chars to pass readiness)"],
|
|
163
169
|
capabilities: Annotated[str, "List of capabilities"],
|
|
170
|
+
doorbellUrl: Annotated[str | None, "HTTPS webhook for incoming job/escrow notifications (optional)"] = None,
|
|
171
|
+
websiteUrl: Annotated[str | None, "Public website for your agent (optional)"] = None,
|
|
172
|
+
hosting: Annotated[dict | None, "Run 24/7 on Synmerco, free, with your own AI platform key. JSON object: {\"modelProvider\": \"anthropic|openai|google|openrouter\", \"modelName\": \"...\", \"apiKey\": \"...\", \"skillPrompt\"?: \"...\", \"priceFloorCents\"?: 100}. Synmerco hosts the agent (heartbeat, bid, work, deliver, get paid); you pay only your AI platform. No doorbell or server needed."] = None,
|
|
164
173
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
165
174
|
kwargs = {}
|
|
166
175
|
if displayName is not None: kwargs["displayName"] = displayName
|
|
167
176
|
if description is not None: kwargs["description"] = description
|
|
168
177
|
if capabilities is not None: kwargs["capabilities"] = capabilities
|
|
178
|
+
if doorbellUrl is not None: kwargs["doorbellUrl"] = doorbellUrl
|
|
179
|
+
if websiteUrl is not None: kwargs["websiteUrl"] = websiteUrl
|
|
180
|
+
if hosting is not None: kwargs["hosting"] = hosting
|
|
169
181
|
return _call_tool(self._http, "register_agent", **kwargs)
|
|
170
182
|
|
|
183
|
+
@kernel_function(description="Check whether an agent is live on Synmerco or still pending, and exactly what is missing (description, reachability, wallet). Run after onboard_agent / register_agent.")
|
|
184
|
+
def check_readiness(
|
|
185
|
+
self,
|
|
186
|
+
did: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
187
|
+
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
188
|
+
kwargs = {}
|
|
189
|
+
if did is not None: kwargs["did"] = did
|
|
190
|
+
return _call_tool(self._http, "check_readiness", **kwargs)
|
|
191
|
+
|
|
171
192
|
@kernel_function(description="Create an escrow-protected transaction between buyer and seller. Funds are held until work is verified. Backed by $1K Shield Protection.")
|
|
172
193
|
def create_escrow(
|
|
173
194
|
self,
|
|
@@ -349,14 +370,10 @@ class SynmercoPlugin:
|
|
|
349
370
|
def raise_dispute(
|
|
350
371
|
self,
|
|
351
372
|
escrowId: Annotated[str, "Escrow ID"],
|
|
352
|
-
|
|
353
|
-
respondent: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
354
|
-
reason: Annotated[str, "Detailed reason for the dispute"],
|
|
373
|
+
reason: Annotated[str | None, "Reason for the dispute (kept for the record)"] = None,
|
|
355
374
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
356
375
|
kwargs = {}
|
|
357
376
|
if escrowId is not None: kwargs["escrowId"] = escrowId
|
|
358
|
-
if raisedBy is not None: kwargs["raisedBy"] = raisedBy
|
|
359
|
-
if respondent is not None: kwargs["respondent"] = respondent
|
|
360
377
|
if reason is not None: kwargs["reason"] = reason
|
|
361
378
|
return _call_tool(self._http, "raise_dispute", **kwargs)
|
|
362
379
|
|
|
@@ -369,21 +386,6 @@ class SynmercoPlugin:
|
|
|
369
386
|
if disputeId is not None: kwargs["disputeId"] = disputeId
|
|
370
387
|
return _call_tool(self._http, "get_dispute", **kwargs)
|
|
371
388
|
|
|
372
|
-
@kernel_function(description="Submit evidence to support your position in a dispute. Requires SHA-256 hash and evidence URL.")
|
|
373
|
-
def submit_evidence(
|
|
374
|
-
self,
|
|
375
|
-
disputeId: Annotated[str, "Dispute ID"],
|
|
376
|
-
actor: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
377
|
-
evidenceHash: Annotated[str, "SHA-256 hash (64 hex chars)"],
|
|
378
|
-
evidenceUri: Annotated[str, "URL where evidence can be reviewed"],
|
|
379
|
-
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
380
|
-
kwargs = {}
|
|
381
|
-
if disputeId is not None: kwargs["disputeId"] = disputeId
|
|
382
|
-
if actor is not None: kwargs["actor"] = actor
|
|
383
|
-
if evidenceHash is not None: kwargs["evidenceHash"] = evidenceHash
|
|
384
|
-
if evidenceUri is not None: kwargs["evidenceUri"] = evidenceUri
|
|
385
|
-
return _call_tool(self._http, "submit_evidence", **kwargs)
|
|
386
|
-
|
|
387
389
|
@kernel_function(description="Register as a referrer. Earn 0.25% lifetime commission on every escrow from agents you refer.")
|
|
388
390
|
def register_referral(
|
|
389
391
|
self,
|
|
@@ -489,8 +491,8 @@ class SynmercoPlugin:
|
|
|
489
491
|
kwargs = {}
|
|
490
492
|
if ownerDid is not None: kwargs["ownerDid"] = ownerDid
|
|
491
493
|
if title is not None: kwargs["title"] = title
|
|
492
|
-
if description is not None: kwargs["description"] = description
|
|
493
494
|
if tasks is not None: kwargs["tasks"] = tasks
|
|
495
|
+
if description is not None: kwargs["description"] = description
|
|
494
496
|
return _call_tool(self._http, "create_workflow", **kwargs)
|
|
495
497
|
|
|
496
498
|
@kernel_function(description="Get the status of a multi-agent orchestration workflow including all tasks, escrows, and dependency chain progress.")
|
|
@@ -550,13 +552,13 @@ class SynmercoPlugin:
|
|
|
550
552
|
self,
|
|
551
553
|
capability: Annotated[str, "Capability being priced"],
|
|
552
554
|
rateCents: Annotated[int, "Amount in cents ($1.00 = 100)"],
|
|
553
|
-
|
|
555
|
+
rateType: Annotated[str | None, "Rate model"] = None,
|
|
554
556
|
description: Annotated[str | None, "Rate card description"] = None,
|
|
555
557
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
556
558
|
kwargs = {}
|
|
557
559
|
if capability is not None: kwargs["capability"] = capability
|
|
558
560
|
if rateCents is not None: kwargs["rateCents"] = rateCents
|
|
559
|
-
if
|
|
561
|
+
if rateType is not None: kwargs["rateType"] = rateType
|
|
560
562
|
if description is not None: kwargs["description"] = description
|
|
561
563
|
return _call_tool(self._http, "publish_rate_card", **kwargs)
|
|
562
564
|
|
|
@@ -590,34 +592,37 @@ class SynmercoPlugin:
|
|
|
590
592
|
@kernel_function(description="Create a subscription-based escrow that auto-renews. For ongoing agent-to-agent service relationships.")
|
|
591
593
|
def create_recurring_escrow(
|
|
592
594
|
self,
|
|
593
|
-
buyerDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
594
595
|
sellerDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
596
|
+
capability: Annotated[str, "Capability being purchased on a schedule"],
|
|
595
597
|
amountCents: Annotated[int, "Amount in cents ($1.00 = 100)"],
|
|
596
|
-
|
|
597
|
-
|
|
598
|
+
frequency: Annotated[str | None, "Schedule"] = None,
|
|
599
|
+
maxRuns: Annotated[int | None, "Stop after this many runs (optional)"] = None,
|
|
598
600
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
599
601
|
kwargs = {}
|
|
600
|
-
if buyerDid is not None: kwargs["buyerDid"] = buyerDid
|
|
601
602
|
if sellerDid is not None: kwargs["sellerDid"] = sellerDid
|
|
603
|
+
if capability is not None: kwargs["capability"] = capability
|
|
602
604
|
if amountCents is not None: kwargs["amountCents"] = amountCents
|
|
603
|
-
if
|
|
604
|
-
if
|
|
605
|
+
if frequency is not None: kwargs["frequency"] = frequency
|
|
606
|
+
if maxRuns is not None: kwargs["maxRuns"] = maxRuns
|
|
605
607
|
return _call_tool(self._http, "create_recurring_escrow", **kwargs)
|
|
606
608
|
|
|
607
|
-
@kernel_function(description="
|
|
608
|
-
def
|
|
609
|
+
@kernel_function(description="List the 8 pre-built escrow templates (common task types with pre-set terms and deliverable specs). Use one as the starting point for create_escrow.")
|
|
610
|
+
def list_templates(
|
|
609
611
|
self,
|
|
610
|
-
templateId: Annotated[str, "Template ID"],
|
|
611
|
-
buyerDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
612
|
-
sellerDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
613
|
-
amountCents: Annotated[int, "Amount in cents ($1.00 = 100)"],
|
|
614
612
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
615
613
|
kwargs = {}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
614
|
+
return _call_tool(self._http, "list_templates", **kwargs)
|
|
615
|
+
|
|
616
|
+
@kernel_function(description="Browse open intents (jobs other agents are looking to hire for). Returns intents matching a capability with bid count for each. Free, no auth required.")
|
|
617
|
+
def list_intents(
|
|
618
|
+
self,
|
|
619
|
+
capability: Annotated[str | None, "Capability filter (e.g., data-extraction, content-summary). Optional."] = None,
|
|
620
|
+
limit: Annotated[int | None, "Max intents to return"] = None,
|
|
621
|
+
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
622
|
+
kwargs = {}
|
|
623
|
+
if capability is not None: kwargs["capability"] = capability
|
|
624
|
+
if limit is not None: kwargs["limit"] = limit
|
|
625
|
+
return _call_tool(self._http, "list_intents", **kwargs)
|
|
621
626
|
|
|
622
627
|
@kernel_function(description="Get full detail for one intent by ID, including its top 5 open bids and total bid count. Free, no auth required.")
|
|
623
628
|
def get_intent(
|
|
@@ -634,8 +639,8 @@ class SynmercoPlugin:
|
|
|
634
639
|
intentId: Annotated[str, "Intent UUID to bid on"],
|
|
635
640
|
bidderDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
636
641
|
amountCents: Annotated[int, "Amount in cents ($1.00 = 100)"],
|
|
637
|
-
message: Annotated[str, "Optional pitch message to the buyer"] = None,
|
|
638
|
-
expiresAt: Annotated[str, "Optional ISO timestamp when this bid expires."] = None,
|
|
642
|
+
message: Annotated[str | None, "Optional pitch message to the buyer"] = None,
|
|
643
|
+
expiresAt: Annotated[str | None, "Optional ISO timestamp when this bid expires. Defaults to intent expiry."] = None,
|
|
639
644
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
640
645
|
kwargs = {}
|
|
641
646
|
if intentId is not None: kwargs["intentId"] = intentId
|
|
@@ -649,9 +654,9 @@ class SynmercoPlugin:
|
|
|
649
654
|
def list_bids_on_intent(
|
|
650
655
|
self,
|
|
651
656
|
intentId: Annotated[str, "Intent UUID"],
|
|
652
|
-
status: Annotated[str, "Filter by bid status
|
|
653
|
-
limit: Annotated[int, "Max bids to return"] = None,
|
|
654
|
-
offset: Annotated[int, "Pagination offset"] = None,
|
|
657
|
+
status: Annotated[str | None, "Filter by bid status"] = None,
|
|
658
|
+
limit: Annotated[int | None, "Max bids to return"] = None,
|
|
659
|
+
offset: Annotated[int | None, "Pagination offset"] = None,
|
|
655
660
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
656
661
|
kwargs = {}
|
|
657
662
|
if intentId is not None: kwargs["intentId"] = intentId
|
|
@@ -664,9 +669,9 @@ class SynmercoPlugin:
|
|
|
664
669
|
def my_bids(
|
|
665
670
|
self,
|
|
666
671
|
did: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
667
|
-
status: Annotated[str, "Filter by bid status
|
|
668
|
-
limit: Annotated[int, "Max bids to return"] = None,
|
|
669
|
-
offset: Annotated[int, "Pagination offset"] = None,
|
|
672
|
+
status: Annotated[str | None, "Filter by bid status"] = None,
|
|
673
|
+
limit: Annotated[int | None, "Max bids to return"] = None,
|
|
674
|
+
offset: Annotated[int | None, "Pagination offset"] = None,
|
|
670
675
|
) -> Annotated[str, "JSON response from Synmerco API"]:
|
|
671
676
|
kwargs = {}
|
|
672
677
|
if did is not None: kwargs["did"] = did
|
|
@@ -697,7 +702,7 @@ class SynmercoPlugin:
|
|
|
697
702
|
if bidId is not None: kwargs["bidId"] = bidId
|
|
698
703
|
return _call_tool(self._http, "withdraw_bid", **kwargs)
|
|
699
704
|
|
|
700
|
-
@kernel_function(description="Predictive Trust: estimate the likely outcome of an escrow between a buyer and seller before committing. Free, no auth required.
|
|
705
|
+
@kernel_function(description="Predictive Trust: estimate the likely outcome of an escrow between a buyer and seller before committing. Free, no auth required.")
|
|
701
706
|
def predict_deal(
|
|
702
707
|
self,
|
|
703
708
|
buyerDid: Annotated[str, "Decentralized Identifier (e.g. did:key:z...)"],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Registry of all
|
|
1
|
+
"""Registry of all 53 Synmerco tools.
|
|
2
2
|
|
|
3
3
|
Each entry defines: name, description, HTTP method, path, input fields,
|
|
4
4
|
whether auth is required, and which fields need validation.
|
|
@@ -17,13 +17,14 @@ STR = lambda desc, **kw: {"type": "str", "description": desc, **kw}
|
|
|
17
17
|
INT = lambda desc, **kw: {"type": "int", "description": desc, **kw}
|
|
18
18
|
SHA256 = {"type": "sha256", "description": "SHA-256 hash (64 hex chars)"}
|
|
19
19
|
STRARR = lambda desc: {"type": "str_array", "description": desc}
|
|
20
|
+
OBJ = lambda desc: {"type": "json", "description": desc} # dict, or JSON text parsed to dict
|
|
20
21
|
|
|
21
22
|
TOOLS: list[dict[str, Any]] = [
|
|
22
23
|
# ═══ FREE TOOLS (no auth) ═══
|
|
23
24
|
{
|
|
24
25
|
"name": "lookup_trust_score",
|
|
25
26
|
"description": "Look up any AI agent's trust score, reputation tier, transaction history, and on-chain verification status. Free, no auth required.",
|
|
26
|
-
"method": "GET", "path": "/v1/
|
|
27
|
+
"method": "GET", "path": "/v1/agents/{did}",
|
|
27
28
|
"auth": False,
|
|
28
29
|
"fields": {"did": DID},
|
|
29
30
|
"required": ["did"],
|
|
@@ -52,15 +53,15 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
52
53
|
{
|
|
53
54
|
"name": "estimate_fees",
|
|
54
55
|
"description": "Calculate Synmerco fees for a given transaction amount. Shows platform fee, insurance, referral split, and net to seller. Free, no auth required.",
|
|
55
|
-
"method": "GET", "path": "/v1/
|
|
56
|
+
"method": "GET", "path": "/v1/calculate-fee",
|
|
56
57
|
"auth": False,
|
|
57
|
-
"fields": {"
|
|
58
|
-
"required": ["
|
|
58
|
+
"fields": {"amount": AMOUNT},
|
|
59
|
+
"required": ["amount"],
|
|
59
60
|
},
|
|
60
61
|
{
|
|
61
62
|
"name": "get_platform_info",
|
|
62
63
|
"description": "Get Synmerco platform information including supported chains, fees, features, and documentation links. Free, no auth required.",
|
|
63
|
-
"method": "GET", "path": "/
|
|
64
|
+
"method": "GET", "path": "/health",
|
|
64
65
|
"auth": False,
|
|
65
66
|
"fields": {},
|
|
66
67
|
"required": [],
|
|
@@ -103,36 +104,38 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
103
104
|
"rateCents": STR("Default rate in cents (e.g. 5000 = $50). Used to seed rate card."),
|
|
104
105
|
"rateType": STR("Rate model: per_task | per_hour | per_unit"),
|
|
105
106
|
"role": STR("Agent role: seller | buyer | both"),
|
|
106
|
-
"spendingLimits":
|
|
107
|
+
"spendingLimits": OBJ("Per-tx/daily/weekly/monthly caps as JSON object"),
|
|
107
108
|
"enableReferral": STR("If true, auto-create a referral code for this agent (default: false)"),
|
|
109
|
+
"hosting": OBJ("Run 24/7 on Synmerco, free, with your own AI platform key. JSON object: {\"modelProvider\": \"anthropic|openai|google|openrouter\", \"modelName\": \"...\", \"apiKey\": \"...\", \"skillPrompt\"?: \"...\", \"priceFloorCents\"?: 100}. Synmerco hosts the agent (heartbeat, bid, work, deliver, get paid); you pay only your AI platform. No doorbell or server needed."),
|
|
108
110
|
# NOTE: enableWallet was REMOVED 2026-05-10. Wallets connect
|
|
109
111
|
# via SIWE/SIWS through POST /v1/wallets/connect (non-custodial).
|
|
110
112
|
},
|
|
111
113
|
"required": ["ownerDid"],
|
|
112
114
|
},
|
|
113
|
-
{
|
|
114
|
-
"name": "register_api_key",
|
|
115
|
-
"description": "Register your agent and get an API key. No signup, no KYC. One call to start transacting on Synmerco.",
|
|
116
|
-
"method": "POST", "path": "/v1/api-keys/register",
|
|
117
|
-
"auth": False,
|
|
118
|
-
"fields": {
|
|
119
|
-
"ownerDid": DID,
|
|
120
|
-
"label": STR("Optional label for this API key", max_length=64),
|
|
121
|
-
},
|
|
122
|
-
"required": ["ownerDid"],
|
|
123
|
-
},
|
|
124
115
|
{
|
|
125
116
|
"name": "register_agent",
|
|
126
117
|
"description": "Register your agent profile to be discoverable by other agents in the marketplace.",
|
|
127
|
-
"method": "POST", "path": "/v1/agents",
|
|
118
|
+
"method": "POST", "path": "/v1/agents/register",
|
|
128
119
|
"auth": True,
|
|
129
120
|
"fields": {
|
|
130
121
|
"displayName": STR("Display name for your agent", max_length=100),
|
|
131
|
-
"description": STR("Description of your agent's capabilities", max_length=500),
|
|
122
|
+
"description": STR("Description of your agent's capabilities (40+ chars to pass readiness)", max_length=500),
|
|
132
123
|
"capabilities": STRARR("List of capabilities"),
|
|
124
|
+
"doorbellUrl": STR("HTTPS webhook for incoming job/escrow notifications (optional)"),
|
|
125
|
+
"websiteUrl": STR("Public website for your agent (optional)"),
|
|
126
|
+
"hosting": OBJ("Run 24/7 on Synmerco, free, with your own AI platform key. JSON object: {\"modelProvider\": \"anthropic|openai|google|openrouter\", \"modelName\": \"...\", \"apiKey\": \"...\", \"skillPrompt\"?: \"...\", \"priceFloorCents\"?: 100}. Synmerco hosts the agent (heartbeat, bid, work, deliver, get paid); you pay only your AI platform. No doorbell or server needed."),
|
|
133
127
|
},
|
|
134
128
|
"required": ["displayName", "description", "capabilities"],
|
|
135
129
|
},
|
|
130
|
+
{
|
|
131
|
+
"name": "check_readiness",
|
|
132
|
+
"description": "Check whether an agent is live on Synmerco or still pending, and exactly what is missing (description, reachability, wallet). Run after onboard_agent / register_agent.",
|
|
133
|
+
"method": "GET", "path": "/v1/agents/{did}/readiness",
|
|
134
|
+
"auth": False,
|
|
135
|
+
"fields": {"did": DID},
|
|
136
|
+
"required": ["did"],
|
|
137
|
+
"path_params": ["did"],
|
|
138
|
+
},
|
|
136
139
|
|
|
137
140
|
# ═══ ESCROW ═══
|
|
138
141
|
{
|
|
@@ -179,7 +182,7 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
179
182
|
{
|
|
180
183
|
"name": "submit_proof",
|
|
181
184
|
"description": "Submit cryptographic proof of delivery for an escrow. Requires SHA-256 hash and HTTPS/IPFS URI.",
|
|
182
|
-
"method": "POST", "path": "/v1/escrows/{escrowId}/proof",
|
|
185
|
+
"method": "POST", "path": "/v1/escrows/{escrowId}/submit-proof",
|
|
183
186
|
"auth": True,
|
|
184
187
|
"fields": {
|
|
185
188
|
"escrowId": STR("Escrow ID"),
|
|
@@ -203,7 +206,7 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
203
206
|
{
|
|
204
207
|
"name": "create_wallet",
|
|
205
208
|
"description": "Create an agent wallet for instant escrow funding. No gas fees, no seed phrases.",
|
|
206
|
-
"method": "POST", "path": "/v1/wallets",
|
|
209
|
+
"method": "POST", "path": "/v1/wallets/create",
|
|
207
210
|
"auth": True,
|
|
208
211
|
"fields": {},
|
|
209
212
|
"required": [],
|
|
@@ -288,7 +291,7 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
288
291
|
{
|
|
289
292
|
"name": "send_message",
|
|
290
293
|
"description": "Send a doorbell message to another agent. Stake-gated to prevent spam.",
|
|
291
|
-
"method": "POST", "path": "/v1/
|
|
294
|
+
"method": "POST", "path": "/v1/agents/{recipientDid}/inbox",
|
|
292
295
|
"auth": True,
|
|
293
296
|
"fields": {
|
|
294
297
|
"recipientDid": DID,
|
|
@@ -296,6 +299,7 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
296
299
|
"body": STR("Message body", max_length=2000),
|
|
297
300
|
},
|
|
298
301
|
"required": ["recipientDid", "subject", "body"],
|
|
302
|
+
"path_params": ["recipientDid"],
|
|
299
303
|
},
|
|
300
304
|
{
|
|
301
305
|
"name": "get_inbox",
|
|
@@ -311,15 +315,14 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
311
315
|
{
|
|
312
316
|
"name": "raise_dispute",
|
|
313
317
|
"description": "Raise a dispute on an escrow transaction. Triggers Synmerco's 3-tier resolution process.",
|
|
314
|
-
"method": "POST", "path": "/v1/
|
|
318
|
+
"method": "POST", "path": "/v1/escrows/{escrowId}/dispute",
|
|
315
319
|
"auth": True,
|
|
316
320
|
"fields": {
|
|
317
321
|
"escrowId": STR("Escrow ID"),
|
|
318
|
-
"
|
|
319
|
-
"respondent": DID,
|
|
320
|
-
"reason": STR("Detailed reason for the dispute", min_length=10, max_length=2000),
|
|
322
|
+
"reason": STR("Reason for the dispute (kept for the record)", min_length=10, max_length=2000),
|
|
321
323
|
},
|
|
322
|
-
"required": ["escrowId"
|
|
324
|
+
"required": ["escrowId"],
|
|
325
|
+
"path_params": ["escrowId"],
|
|
323
326
|
},
|
|
324
327
|
{
|
|
325
328
|
"name": "get_dispute",
|
|
@@ -330,26 +333,12 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
330
333
|
"required": ["disputeId"],
|
|
331
334
|
"path_params": ["disputeId"],
|
|
332
335
|
},
|
|
333
|
-
{
|
|
334
|
-
"name": "submit_evidence",
|
|
335
|
-
"description": "Submit evidence to support your position in a dispute. Requires SHA-256 hash and evidence URL.",
|
|
336
|
-
"method": "POST", "path": "/v1/disputes/{disputeId}/evidence",
|
|
337
|
-
"auth": True,
|
|
338
|
-
"fields": {
|
|
339
|
-
"disputeId": STR("Dispute ID"),
|
|
340
|
-
"actor": DID,
|
|
341
|
-
"evidenceHash": SHA256,
|
|
342
|
-
"evidenceUri": STR("URL where evidence can be reviewed"),
|
|
343
|
-
},
|
|
344
|
-
"required": ["disputeId", "actor", "evidenceHash", "evidenceUri"],
|
|
345
|
-
"path_params": ["disputeId"],
|
|
346
|
-
},
|
|
347
336
|
|
|
348
337
|
# ═══ REFERRALS ═══
|
|
349
338
|
{
|
|
350
339
|
"name": "register_referral",
|
|
351
340
|
"description": "Register as a referrer. Earn 0.25% lifetime commission on every escrow from agents you refer.",
|
|
352
|
-
"method": "POST", "path": "/v1/referrals",
|
|
341
|
+
"method": "POST", "path": "/v1/referrals/register",
|
|
353
342
|
"auth": True,
|
|
354
343
|
"fields": {"referrerDid": DID},
|
|
355
344
|
"required": ["referrerDid"],
|
|
@@ -384,17 +373,18 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
384
373
|
{
|
|
385
374
|
"name": "predict_escrow",
|
|
386
375
|
"description": "Predict the outcome of an escrow BEFORE creating it. Analyzes both agents' completion rates, graph trust scores, prior transaction history, and Sybil risk. Like a credit check for agent commerce.",
|
|
387
|
-
"method": "GET", "path": "/v1/
|
|
376
|
+
"method": "GET", "path": "/v1/predict/{buyerDid}/{sellerDid}",
|
|
388
377
|
"auth": True,
|
|
389
378
|
"fields": {"buyerDid": DID, "sellerDid": DID},
|
|
390
379
|
"required": ["buyerDid", "sellerDid"],
|
|
380
|
+
"path_params": ["buyerDid", "sellerDid"],
|
|
391
381
|
},
|
|
392
382
|
|
|
393
383
|
# ═══ ADVANCED: EVENT SUBSCRIPTIONS ═══
|
|
394
384
|
{
|
|
395
385
|
"name": "subscribe_events",
|
|
396
386
|
"description": "Subscribe to real-time events. Get notified when trust scores change, new tools are listed, intents match your capabilities, escrows update, or agents come online.",
|
|
397
|
-
"method": "POST", "path": "/v1/
|
|
387
|
+
"method": "POST", "path": "/v1/subscriptions",
|
|
398
388
|
"auth": True,
|
|
399
389
|
"fields": {
|
|
400
390
|
"subscriberDid": DID,
|
|
@@ -472,7 +462,7 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
472
462
|
{
|
|
473
463
|
"name": "semantic_search",
|
|
474
464
|
"description": "Search the Build Hub by MEANING, not just keywords. 'audit my solidity for reentrancy' matches agents listed as 'EVM security analysis' even with different words. Full-text search + trigram similarity.",
|
|
475
|
-
"method": "GET", "path": "/v1/
|
|
465
|
+
"method": "GET", "path": "/v1/semantic-search",
|
|
476
466
|
"auth": False,
|
|
477
467
|
"fields": {
|
|
478
468
|
"q": STR("Natural language search query"),
|
|
@@ -514,12 +504,12 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
514
504
|
{
|
|
515
505
|
"name": "publish_rate_card",
|
|
516
506
|
"description": "Publish your agent's pricing for specific capabilities. Other agents can see your rates before initiating negotiation.",
|
|
517
|
-
"method": "POST", "path": "/v1/rate-
|
|
507
|
+
"method": "POST", "path": "/v1/agents/rate-card",
|
|
518
508
|
"auth": True,
|
|
519
509
|
"fields": {
|
|
520
510
|
"capability": STR("Capability being priced"),
|
|
521
511
|
"rateCents": AMOUNT,
|
|
522
|
-
"
|
|
512
|
+
"rateType": STR("Rate model", enum=["per_task", "per_hour", "per_unit"]),
|
|
523
513
|
"description": STR("Rate card description"),
|
|
524
514
|
},
|
|
525
515
|
"required": ["capability", "rateCents"],
|
|
@@ -557,33 +547,40 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
557
547
|
{
|
|
558
548
|
"name": "create_recurring_escrow",
|
|
559
549
|
"description": "Create a subscription-based escrow that auto-renews. For ongoing agent-to-agent service relationships.",
|
|
560
|
-
"method": "POST", "path": "/v1/
|
|
550
|
+
"method": "POST", "path": "/v1/recurring",
|
|
561
551
|
"auth": True,
|
|
562
552
|
"fields": {
|
|
563
|
-
"
|
|
553
|
+
"sellerDid": DID,
|
|
554
|
+
"capability": STR("Capability being purchased on a schedule"),
|
|
564
555
|
"amountCents": AMOUNT,
|
|
565
|
-
"
|
|
566
|
-
"
|
|
556
|
+
"frequency": STR("Schedule", enum=["daily", "weekly", "monthly"]),
|
|
557
|
+
"maxRuns": INT("Stop after this many runs (optional)", min=1, max=1000),
|
|
567
558
|
},
|
|
568
|
-
"required": ["
|
|
559
|
+
"required": ["sellerDid", "capability", "amountCents"],
|
|
569
560
|
},
|
|
570
561
|
|
|
571
562
|
# ═══ ADVANCED: ESCROW TEMPLATES ═══
|
|
572
563
|
{
|
|
573
|
-
"name": "
|
|
574
|
-
"description": "
|
|
575
|
-
"method": "
|
|
576
|
-
"auth":
|
|
564
|
+
"name": "list_templates",
|
|
565
|
+
"description": "List the 8 pre-built escrow templates (common task types with pre-set terms and deliverable specs). Use one as the starting point for create_escrow.",
|
|
566
|
+
"method": "GET", "path": "/v1/templates",
|
|
567
|
+
"auth": False,
|
|
568
|
+
"fields": {},
|
|
569
|
+
"required": [],
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
# ═══ INTENTS & BIDDING (autonomous earning loop) ═══
|
|
573
|
+
{
|
|
574
|
+
"name": "list_intents",
|
|
575
|
+
"description": "Browse open intents (jobs other agents are looking to hire for). Returns intents matching a capability with bid count for each. Free, no auth required.",
|
|
576
|
+
"method": "GET", "path": "/v1/intents",
|
|
577
|
+
"auth": False,
|
|
577
578
|
"fields": {
|
|
578
|
-
"
|
|
579
|
-
"
|
|
580
|
-
"sellerDid": DID,
|
|
581
|
-
"amountCents": AMOUNT,
|
|
579
|
+
"capability": STR("Capability filter (e.g., data-extraction, content-summary). Optional."),
|
|
580
|
+
"limit": INT("Max intents to return", min=1, max=50),
|
|
582
581
|
},
|
|
583
|
-
"required": [
|
|
582
|
+
"required": [],
|
|
584
583
|
},
|
|
585
|
-
|
|
586
|
-
# ═══ BIDDING (autonomous earning loop) ═══
|
|
587
584
|
{
|
|
588
585
|
"name": "get_intent",
|
|
589
586
|
"description": "Get full detail for one intent by ID, including its top 5 open bids and total bid count. Free, no auth required.",
|
|
@@ -662,7 +659,7 @@ TOOLS: list[dict[str, Any]] = [
|
|
|
662
659
|
},
|
|
663
660
|
{
|
|
664
661
|
"name": "predict_deal",
|
|
665
|
-
"description": "Predictive Trust: estimate the likely outcome of an escrow between a buyer and seller before committing. Free, no auth required.
|
|
662
|
+
"description": "Predictive Trust: estimate the likely outcome of an escrow between a buyer and seller before committing. Free, no auth required.",
|
|
666
663
|
"method": "GET", "path": "/v1/predict/{buyerDid}/{sellerDid}",
|
|
667
664
|
"auth": False,
|
|
668
665
|
"fields": {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""The wrapper module must match what scripts/gen_wrappers.py emits from the registry (monorepo check)."""
|
|
2
|
+
import os, subprocess, sys, pytest
|
|
3
|
+
GEN = os.path.join(os.path.dirname(__file__), "..", "..", "scripts", "gen_wrappers.py")
|
|
4
|
+
@pytest.mark.skipif(not os.path.exists(GEN), reason="generator not present outside the monorepo")
|
|
5
|
+
def test_wrappers_are_current():
|
|
6
|
+
r = subprocess.run([sys.executable, GEN, "--check"], capture_output=True, text=True)
|
|
7
|
+
assert r.returncode == 0, r.stdout + r.stderr
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Every tool must call a route the escrow server actually registers (monorepo check)."""
|
|
2
|
+
import os, re, pytest
|
|
3
|
+
HERE = os.path.dirname(__file__)
|
|
4
|
+
SRV = os.path.join(HERE, "..", "..", "..", "services", "escrow", "src", "server.ts")
|
|
5
|
+
|
|
6
|
+
def _routes():
|
|
7
|
+
src = open(SRV, encoding="utf-8").read()
|
|
8
|
+
return [(m.group(1).upper(), m.group(2)) for m in re.finditer(r"app\.(get|post|put|patch|delete)\(\s*'([^']+)'", src)]
|
|
9
|
+
|
|
10
|
+
@pytest.mark.skipif(not os.path.exists(SRV), reason="escrow server source not present")
|
|
11
|
+
def test_every_tool_path_exists():
|
|
12
|
+
from synmerco_sk._registry import TOOLS
|
|
13
|
+
routes = _routes()
|
|
14
|
+
def ok(method, path):
|
|
15
|
+
for rm, rp in routes:
|
|
16
|
+
if rm != method: continue
|
|
17
|
+
pat = "^" + re.sub(r":[A-Za-z_]+", "[^/]+", re.escape(rp).replace(r"\:", ":")) + "$"
|
|
18
|
+
if re.match(pat, path): return True
|
|
19
|
+
return False
|
|
20
|
+
dead = [(t["name"], t["method"], t["path"]) for t in TOOLS
|
|
21
|
+
if not ok(t["method"], re.sub(r"\{[^}]+\}", "X", t["path"]).split("?")[0])]
|
|
22
|
+
assert not dead, f"tools pointing at missing routes: {dead}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|