portage-ucp-client 0.1.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -1
- data/lib/portage/ucp/client/session.rb +48 -23
- data/lib/portage/ucp/client/transports/http.rb +2 -2
- data/lib/portage/ucp/client/transports/loopback.rb +3 -2
- data/lib/portage/ucp/client/transports/stdio.rb +2 -2
- data/lib/portage/ucp/client/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8ca449d6a513f5b79171362c5fbd7830812fecf99abc5b60d88e98c6362faf10
|
|
4
|
+
data.tar.gz: fa8e0a0f2a00f3b62431303aafabfb94228e9fecae184c1d5ab9df3752240b46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 15a8962035eef888342055b2307304c89fa97e180c1a2ebb70e9ae25cbf8bd35212d95f1b83a09afa0d27c0a6003bba92b3a844fc58145b04d0eed759fc4d366
|
|
7
|
+
data.tar.gz: ed79009feffcc06418784907007b210250edc1e95182c48a8c8408f8de3db226da082cc55f3d50bc532707ebe682618a4b7040963001c963c068497a12a79364
|
data/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,34 @@ All notable changes to this project are documented here. Format loosely follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/); this project is
|
|
5
5
|
pre-1.0, so APIs may still shift between minor versions.
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.3.0] - 2026-09-14
|
|
10
|
+
|
|
11
|
+
- `Session` gains `#create_payment_enrollment(idempotency_key: nil)` /
|
|
12
|
+
`#get_payment_enrollment(enrollment_id:)`, covering the new
|
|
13
|
+
`app.portage-ucp.payment_enrollment` capability (docs/plans/agentic-payments.md
|
|
14
|
+
Phase 1). `create_payment_enrollment` is added to `MUTATING_ACTIONS`, so a
|
|
15
|
+
caller that omits `idempotency_key:` still gets one generated.
|
|
16
|
+
- Every transport (http, stdio, loopback) and `Session` grow an optional
|
|
17
|
+
`meta:` kwarg, threaded through the same way `correlation_id` already
|
|
18
|
+
reaches the server from `traceparent` — additive only, no caller passing
|
|
19
|
+
`meta:` is required to change.
|
|
20
|
+
- Widened the `portage-ucp` dependency pin from `~> 0.4` to `~> 0.5` —
|
|
21
|
+
`#create_payment_enrollment`/`#get_payment_enrollment` need the
|
|
22
|
+
`app.portage-ucp.payment_enrollment` capability, only present from
|
|
23
|
+
`portage-ucp` 0.5.0 on.
|
|
24
|
+
|
|
25
|
+
## [0.2.0] - 2026-08-21
|
|
26
|
+
|
|
27
|
+
- `Session#create_checkout`/`#update_checkout` gain an optional `fulfillment:`
|
|
28
|
+
param, passed through only when given. Only exercised end-to-end over the
|
|
29
|
+
loopback transport (an in-process `Adapter`, taking a real
|
|
30
|
+
`Portage::Ucp::CheckoutFulfillment`); the stdio/HTTP wire shape for
|
|
31
|
+
`fulfillment` has no real UCP server to verify it against yet, so it's not
|
|
32
|
+
wired there.
|
|
33
|
+
|
|
34
|
+
## [0.1.0] - 2026-08-14
|
|
8
35
|
|
|
9
36
|
- Initial pre-release. Client-side SDK — loopback, stdio, and Streamable HTTP
|
|
10
37
|
transports behind one `Session` interface.
|
|
@@ -18,7 +18,7 @@ module Portage
|
|
|
18
18
|
# must branch on it themselves.
|
|
19
19
|
class Session
|
|
20
20
|
MUTATING_ACTIONS = %w[create_cart update_cart cancel_cart create_checkout update_checkout
|
|
21
|
-
complete_checkout cancel_checkout].freeze
|
|
21
|
+
complete_checkout cancel_checkout create_payment_enrollment].freeze
|
|
22
22
|
|
|
23
23
|
# @param capabilities [Array<String>, nil] reverse-domain capability
|
|
24
24
|
# names advertised by the server, when known upfront (Client.discover
|
|
@@ -38,51 +38,76 @@ module Portage
|
|
|
38
38
|
capabilities&.include?(capability_name)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def search_catalog(query:, limit: 20
|
|
42
|
-
|
|
41
|
+
def search_catalog(query:, limit: 20,
|
|
42
|
+
meta: nil)
|
|
43
|
+
call("search_catalog", meta: meta, query: query, limit: limit)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def get_product(product_id:, meta: nil) = call("get_product", meta: meta, product_id: product_id)
|
|
47
|
+
def lookup_catalog(product_ids:, meta: nil) = call("lookup_catalog", meta: meta, product_ids: product_ids)
|
|
43
48
|
|
|
44
|
-
def get_cart(cart_id:) = call("get_cart", cart_id: cart_id)
|
|
49
|
+
def get_cart(cart_id:, meta: nil) = call("get_cart", meta: meta, cart_id: cart_id)
|
|
45
50
|
|
|
46
|
-
def create_cart(line_items:, idempotency_key: nil)
|
|
47
|
-
call("create_cart", line_items: line_items, idempotency_key: idempotency_key)
|
|
51
|
+
def create_cart(line_items:, idempotency_key: nil, meta: nil)
|
|
52
|
+
call("create_cart", meta: meta, line_items: line_items, idempotency_key: idempotency_key)
|
|
48
53
|
end
|
|
49
54
|
|
|
50
|
-
def update_cart(cart_id:, line_items:, idempotency_key: nil)
|
|
51
|
-
call("update_cart", cart_id: cart_id, line_items: line_items, idempotency_key: idempotency_key)
|
|
55
|
+
def update_cart(cart_id:, line_items:, idempotency_key: nil, meta: nil)
|
|
56
|
+
call("update_cart", meta: meta, cart_id: cart_id, line_items: line_items, idempotency_key: idempotency_key)
|
|
52
57
|
end
|
|
53
58
|
|
|
54
|
-
def cancel_cart(cart_id:, idempotency_key: nil)
|
|
55
|
-
call("cancel_cart", cart_id: cart_id, idempotency_key: idempotency_key)
|
|
59
|
+
def cancel_cart(cart_id:, idempotency_key: nil, meta: nil)
|
|
60
|
+
call("cancel_cart", meta: meta, cart_id: cart_id, idempotency_key: idempotency_key)
|
|
56
61
|
end
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
# `fulfillment:` (dev.ucp.shopping.fulfillment) is only exercised over
|
|
64
|
+
# the loopback transport today (Portage::Cli::Buy's own-store adapter
|
|
65
|
+
# path) — passed straight through as whatever value the caller built
|
|
66
|
+
# (a Portage::Ucp::CheckoutFulfillment for loopback). Over stdio/HTTP
|
|
67
|
+
# it would need a JSON wire shape this gem doesn't build yet, so
|
|
68
|
+
# callers on those transports should leave it nil.
|
|
69
|
+
def create_checkout(line_items:, idempotency_key: nil, fulfillment: nil, meta: nil)
|
|
70
|
+
call("create_checkout", meta: meta, line_items: line_items, idempotency_key: idempotency_key,
|
|
71
|
+
**(fulfillment ? { fulfillment: fulfillment } : {}))
|
|
60
72
|
end
|
|
61
73
|
|
|
62
|
-
def get_checkout(checkout_id:) = call("get_checkout", checkout_id: checkout_id)
|
|
74
|
+
def get_checkout(checkout_id:, meta: nil) = call("get_checkout", meta: meta, checkout_id: checkout_id)
|
|
63
75
|
|
|
64
|
-
def update_checkout(checkout_id:, line_items:, idempotency_key: nil)
|
|
65
|
-
call("update_checkout", checkout_id: checkout_id, line_items: line_items,
|
|
76
|
+
def update_checkout(checkout_id:, line_items:, idempotency_key: nil, fulfillment: nil, meta: nil)
|
|
77
|
+
call("update_checkout", meta: meta, checkout_id: checkout_id, line_items: line_items,
|
|
78
|
+
idempotency_key: idempotency_key,
|
|
79
|
+
**(fulfillment ? { fulfillment: fulfillment } : {}))
|
|
66
80
|
end
|
|
67
81
|
|
|
68
|
-
def complete_checkout(checkout_id:, payment_token:, idempotency_key: nil)
|
|
82
|
+
def complete_checkout(checkout_id:, payment_token:, idempotency_key: nil, meta: nil)
|
|
69
83
|
Portage::Ucp::PaymentTokenGuard.validate!(payment_token)
|
|
70
|
-
call("complete_checkout", checkout_id: checkout_id, payment_token: payment_token,
|
|
84
|
+
call("complete_checkout", meta: meta, checkout_id: checkout_id, payment_token: payment_token,
|
|
71
85
|
idempotency_key: idempotency_key)
|
|
72
86
|
end
|
|
73
87
|
|
|
74
|
-
def cancel_checkout(checkout_id:, idempotency_key: nil)
|
|
75
|
-
call("cancel_checkout", checkout_id: checkout_id, idempotency_key: idempotency_key)
|
|
88
|
+
def cancel_checkout(checkout_id:, idempotency_key: nil, meta: nil)
|
|
89
|
+
call("cancel_checkout", meta: meta, checkout_id: checkout_id, idempotency_key: idempotency_key)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def get_order(order_id:, meta: nil) = call("get_order", meta: meta, order_id: order_id)
|
|
93
|
+
def link_identity(oauth_token:, meta: nil) = call("link_identity", meta: meta, oauth_token: oauth_token)
|
|
94
|
+
|
|
95
|
+
# app.portage-ucp.payment_enrollment (Portage extension, §ref
|
|
96
|
+
# docs/plans/agentic-payments.md Phase 1) — not every adapter
|
|
97
|
+
# advertises this, check #advertises? first.
|
|
98
|
+
def create_payment_enrollment(idempotency_key: nil, meta: nil)
|
|
99
|
+
call("create_payment_enrollment", meta: meta, idempotency_key: idempotency_key)
|
|
76
100
|
end
|
|
77
101
|
|
|
78
|
-
def
|
|
79
|
-
|
|
102
|
+
def get_payment_enrollment(enrollment_id:, meta: nil)
|
|
103
|
+
call("get_payment_enrollment", meta: meta, enrollment_id: enrollment_id)
|
|
104
|
+
end
|
|
80
105
|
|
|
81
106
|
private
|
|
82
107
|
|
|
83
|
-
def call(action, **arguments)
|
|
108
|
+
def call(action, meta: nil, **arguments)
|
|
84
109
|
arguments[:idempotency_key] ||= SecureRandom.uuid if MUTATING_ACTIONS.include?(action)
|
|
85
|
-
@transport.call_tool(name: action, arguments: arguments)
|
|
110
|
+
@transport.call_tool(name: action, arguments: arguments, meta: meta)
|
|
86
111
|
end
|
|
87
112
|
end
|
|
88
113
|
end
|
|
@@ -12,8 +12,8 @@ module Portage
|
|
|
12
12
|
@client.connect
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def call_tool(name:, arguments:)
|
|
16
|
-
response = @client.call_tool(name: name, arguments: arguments)
|
|
15
|
+
def call_tool(name:, arguments:, meta: nil)
|
|
16
|
+
response = @client.call_tool(name: name, arguments: arguments, meta: meta)
|
|
17
17
|
ToolResult.extract(response, symbol_keys: false)
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -15,10 +15,11 @@ module Portage
|
|
|
15
15
|
@next_id = 0
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def call_tool(name:, arguments:)
|
|
18
|
+
def call_tool(name:, arguments:, meta: nil)
|
|
19
19
|
@next_id += 1
|
|
20
20
|
response = @server.handle(
|
|
21
|
-
{ jsonrpc: "2.0", id: @next_id, method: "tools/call",
|
|
21
|
+
{ jsonrpc: "2.0", id: @next_id, method: "tools/call",
|
|
22
|
+
params: { name: name, arguments: arguments, **(meta ? { _meta: meta } : {}) } }
|
|
22
23
|
)
|
|
23
24
|
ToolResult.extract(response, symbol_keys: true)
|
|
24
25
|
end
|
|
@@ -12,8 +12,8 @@ module Portage
|
|
|
12
12
|
@client.connect
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def call_tool(name:, arguments:)
|
|
16
|
-
response = @client.call_tool(name: name, arguments: arguments)
|
|
15
|
+
def call_tool(name:, arguments:, meta: nil)
|
|
16
|
+
response = @client.call_tool(name: name, arguments: arguments, meta: meta)
|
|
17
17
|
ToolResult.extract(response, symbol_keys: false)
|
|
18
18
|
end
|
|
19
19
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: portage-ucp-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tom Whitbread
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: mcp
|
|
@@ -30,14 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0.
|
|
33
|
+
version: '0.5'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0.
|
|
40
|
+
version: '0.5'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rspec
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|