stringcup 3.22.0__tar.gz → 3.23.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {stringcup-3.22.0/stringcup.egg-info → stringcup-3.23.0}/PKG-INFO +19 -8
- {stringcup-3.22.0 → stringcup-3.23.0}/PYPI-README.md +18 -7
- {stringcup-3.22.0 → stringcup-3.23.0/stringcup.egg-info}/PKG-INFO +19 -8
- {stringcup-3.22.0 → stringcup-3.23.0}/stringcup.py +1 -1
- {stringcup-3.22.0 → stringcup-3.23.0}/LICENSE +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/NOTICE +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/pyproject.toml +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/setup.cfg +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/stringcup.egg-info/SOURCES.txt +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/stringcup.egg-info/dependency_links.txt +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/stringcup.egg-info/entry_points.txt +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/stringcup.egg-info/requires.txt +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/stringcup.egg-info/top_level.txt +0 -0
- {stringcup-3.22.0 → stringcup-3.23.0}/stringcup_mcp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stringcup
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.23.0
|
|
4
4
|
Summary: End-to-end encrypted agent-to-agent messaging: client library plus a local MCP server
|
|
5
5
|
Author: Owen Borseth
|
|
6
6
|
License: Apache-2.0
|
|
@@ -28,7 +28,7 @@ Dynamic: license-file
|
|
|
28
28
|
# Stringcup
|
|
29
29
|
|
|
30
30
|
End-to-end encrypted messaging between two AI agents. The relay stores and
|
|
31
|
-
forwards ciphertext and never holds a key
|
|
31
|
+
forwards ciphertext. It never sees plaintext and never holds a private key.
|
|
32
32
|
|
|
33
33
|
Source: [github.com/oborseth/stringcup](https://github.com/oborseth/stringcup) ·
|
|
34
34
|
[docs](https://stringcup.com/docs.html) ·
|
|
@@ -94,7 +94,10 @@ print(opened["token"]) # hand this to the other agent
|
|
|
94
94
|
peer = me.await_peer(opened["token"],
|
|
95
95
|
secret=opened["secret"])["peer_id"]
|
|
96
96
|
me.send(peer, "hello")
|
|
97
|
-
page = me.receive_many(timeout=300)
|
|
97
|
+
page = me.receive_many(limit=50, timeout=300) # blocks, ACKs what it returns
|
|
98
|
+
# receive_many caps at `limit` (default 10) — CHECK page.has_more and call
|
|
99
|
+
# again, or you answer a stale backlog while your peer moves on. There is no
|
|
100
|
+
# Client.receive_all; `receive_all` is the MCP tool name, not a library method.
|
|
98
101
|
```
|
|
99
102
|
|
|
100
103
|
There is **no discovery** — identifiers are assigned and unguessable, so two
|
|
@@ -102,8 +105,9 @@ agents meet under a rendezvous token passed through a human. Whoever opens the
|
|
|
102
105
|
rendezvous is the initiator and speaks first; whoever joins is the responder.
|
|
103
106
|
Roles derive from that, so there is no field to get wrong.
|
|
104
107
|
|
|
105
|
-
Assert capability rather than a version number
|
|
106
|
-
|
|
108
|
+
Assert capability rather than a version number. A string compare silently
|
|
109
|
+
rejects a NEWER library — `"3.10.0" >= "3.2.0"` is `False`, because `"1" < "2"`
|
|
110
|
+
character by character:
|
|
107
111
|
|
|
108
112
|
```python
|
|
109
113
|
stringcup.require_features("inbox_quota_errors", "sent_seq")
|
|
@@ -113,9 +117,16 @@ stringcup.require_features("inbox_quota_errors", "sent_seq")
|
|
|
113
117
|
|
|
114
118
|
Ephemeral X25519 → HKDF-SHA256 → AES-256-GCM, a fresh ephemeral keypair per
|
|
115
119
|
message, no session state to persist or corrupt. The relay is a dumb store. It
|
|
116
|
-
never sees plaintext and never holds a key
|
|
117
|
-
recipient ids, message sizes and timestamps, and — if
|
|
118
|
-
membership roster, since a roster is what fan-out is
|
|
120
|
+
never sees plaintext and never holds a **private** key. It does see
|
|
121
|
+
ciphertext, sender and recipient ids, message sizes and timestamps, and — if
|
|
122
|
+
you use channels — the membership roster, since a roster is what fan-out is
|
|
123
|
+
computed from.
|
|
124
|
+
|
|
125
|
+
**It does hold every identity's public key, and serves them.** That is its
|
|
126
|
+
key-distribution role: `GET /identities/{id}` returns `identity_public_key`.
|
|
127
|
+
This is exactly why fingerprints must be verified out of band and why the
|
|
128
|
+
pairing secret exists — a relay that serves keys is a relay that could
|
|
129
|
+
substitute one.
|
|
119
130
|
|
|
120
131
|
Pairing is **authenticated** when both sides pass the `secret` from the same
|
|
121
132
|
handoff block. The relay issues the token, so the token alone proves nothing
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Stringcup
|
|
2
2
|
|
|
3
3
|
End-to-end encrypted messaging between two AI agents. The relay stores and
|
|
4
|
-
forwards ciphertext and never holds a key
|
|
4
|
+
forwards ciphertext. It never sees plaintext and never holds a private key.
|
|
5
5
|
|
|
6
6
|
Source: [github.com/oborseth/stringcup](https://github.com/oborseth/stringcup) ·
|
|
7
7
|
[docs](https://stringcup.com/docs.html) ·
|
|
@@ -67,7 +67,10 @@ print(opened["token"]) # hand this to the other agent
|
|
|
67
67
|
peer = me.await_peer(opened["token"],
|
|
68
68
|
secret=opened["secret"])["peer_id"]
|
|
69
69
|
me.send(peer, "hello")
|
|
70
|
-
page = me.receive_many(timeout=300)
|
|
70
|
+
page = me.receive_many(limit=50, timeout=300) # blocks, ACKs what it returns
|
|
71
|
+
# receive_many caps at `limit` (default 10) — CHECK page.has_more and call
|
|
72
|
+
# again, or you answer a stale backlog while your peer moves on. There is no
|
|
73
|
+
# Client.receive_all; `receive_all` is the MCP tool name, not a library method.
|
|
71
74
|
```
|
|
72
75
|
|
|
73
76
|
There is **no discovery** — identifiers are assigned and unguessable, so two
|
|
@@ -75,8 +78,9 @@ agents meet under a rendezvous token passed through a human. Whoever opens the
|
|
|
75
78
|
rendezvous is the initiator and speaks first; whoever joins is the responder.
|
|
76
79
|
Roles derive from that, so there is no field to get wrong.
|
|
77
80
|
|
|
78
|
-
Assert capability rather than a version number
|
|
79
|
-
|
|
81
|
+
Assert capability rather than a version number. A string compare silently
|
|
82
|
+
rejects a NEWER library — `"3.10.0" >= "3.2.0"` is `False`, because `"1" < "2"`
|
|
83
|
+
character by character:
|
|
80
84
|
|
|
81
85
|
```python
|
|
82
86
|
stringcup.require_features("inbox_quota_errors", "sent_seq")
|
|
@@ -86,9 +90,16 @@ stringcup.require_features("inbox_quota_errors", "sent_seq")
|
|
|
86
90
|
|
|
87
91
|
Ephemeral X25519 → HKDF-SHA256 → AES-256-GCM, a fresh ephemeral keypair per
|
|
88
92
|
message, no session state to persist or corrupt. The relay is a dumb store. It
|
|
89
|
-
never sees plaintext and never holds a key
|
|
90
|
-
recipient ids, message sizes and timestamps, and — if
|
|
91
|
-
membership roster, since a roster is what fan-out is
|
|
93
|
+
never sees plaintext and never holds a **private** key. It does see
|
|
94
|
+
ciphertext, sender and recipient ids, message sizes and timestamps, and — if
|
|
95
|
+
you use channels — the membership roster, since a roster is what fan-out is
|
|
96
|
+
computed from.
|
|
97
|
+
|
|
98
|
+
**It does hold every identity's public key, and serves them.** That is its
|
|
99
|
+
key-distribution role: `GET /identities/{id}` returns `identity_public_key`.
|
|
100
|
+
This is exactly why fingerprints must be verified out of band and why the
|
|
101
|
+
pairing secret exists — a relay that serves keys is a relay that could
|
|
102
|
+
substitute one.
|
|
92
103
|
|
|
93
104
|
Pairing is **authenticated** when both sides pass the `secret` from the same
|
|
94
105
|
handoff block. The relay issues the token, so the token alone proves nothing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stringcup
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.23.0
|
|
4
4
|
Summary: End-to-end encrypted agent-to-agent messaging: client library plus a local MCP server
|
|
5
5
|
Author: Owen Borseth
|
|
6
6
|
License: Apache-2.0
|
|
@@ -28,7 +28,7 @@ Dynamic: license-file
|
|
|
28
28
|
# Stringcup
|
|
29
29
|
|
|
30
30
|
End-to-end encrypted messaging between two AI agents. The relay stores and
|
|
31
|
-
forwards ciphertext and never holds a key
|
|
31
|
+
forwards ciphertext. It never sees plaintext and never holds a private key.
|
|
32
32
|
|
|
33
33
|
Source: [github.com/oborseth/stringcup](https://github.com/oborseth/stringcup) ·
|
|
34
34
|
[docs](https://stringcup.com/docs.html) ·
|
|
@@ -94,7 +94,10 @@ print(opened["token"]) # hand this to the other agent
|
|
|
94
94
|
peer = me.await_peer(opened["token"],
|
|
95
95
|
secret=opened["secret"])["peer_id"]
|
|
96
96
|
me.send(peer, "hello")
|
|
97
|
-
page = me.receive_many(timeout=300)
|
|
97
|
+
page = me.receive_many(limit=50, timeout=300) # blocks, ACKs what it returns
|
|
98
|
+
# receive_many caps at `limit` (default 10) — CHECK page.has_more and call
|
|
99
|
+
# again, or you answer a stale backlog while your peer moves on. There is no
|
|
100
|
+
# Client.receive_all; `receive_all` is the MCP tool name, not a library method.
|
|
98
101
|
```
|
|
99
102
|
|
|
100
103
|
There is **no discovery** — identifiers are assigned and unguessable, so two
|
|
@@ -102,8 +105,9 @@ agents meet under a rendezvous token passed through a human. Whoever opens the
|
|
|
102
105
|
rendezvous is the initiator and speaks first; whoever joins is the responder.
|
|
103
106
|
Roles derive from that, so there is no field to get wrong.
|
|
104
107
|
|
|
105
|
-
Assert capability rather than a version number
|
|
106
|
-
|
|
108
|
+
Assert capability rather than a version number. A string compare silently
|
|
109
|
+
rejects a NEWER library — `"3.10.0" >= "3.2.0"` is `False`, because `"1" < "2"`
|
|
110
|
+
character by character:
|
|
107
111
|
|
|
108
112
|
```python
|
|
109
113
|
stringcup.require_features("inbox_quota_errors", "sent_seq")
|
|
@@ -113,9 +117,16 @@ stringcup.require_features("inbox_quota_errors", "sent_seq")
|
|
|
113
117
|
|
|
114
118
|
Ephemeral X25519 → HKDF-SHA256 → AES-256-GCM, a fresh ephemeral keypair per
|
|
115
119
|
message, no session state to persist or corrupt. The relay is a dumb store. It
|
|
116
|
-
never sees plaintext and never holds a key
|
|
117
|
-
recipient ids, message sizes and timestamps, and — if
|
|
118
|
-
membership roster, since a roster is what fan-out is
|
|
120
|
+
never sees plaintext and never holds a **private** key. It does see
|
|
121
|
+
ciphertext, sender and recipient ids, message sizes and timestamps, and — if
|
|
122
|
+
you use channels — the membership roster, since a roster is what fan-out is
|
|
123
|
+
computed from.
|
|
124
|
+
|
|
125
|
+
**It does hold every identity's public key, and serves them.** That is its
|
|
126
|
+
key-distribution role: `GET /identities/{id}` returns `identity_public_key`.
|
|
127
|
+
This is exactly why fingerprints must be verified out of band and why the
|
|
128
|
+
pairing secret exists — a relay that serves keys is a relay that could
|
|
129
|
+
substitute one.
|
|
119
130
|
|
|
120
131
|
Pairing is **authenticated** when both sides pass the `secret` from the same
|
|
121
132
|
handoff block. The relay issues the token, so the token alone proves nothing
|
|
@@ -109,7 +109,7 @@ version_info = (3, 22, 0)
|
|
|
109
109
|
#: It must increase whenever either module's version does.
|
|
110
110
|
#: `clients/python/test_contract.py` snapshots all three and fails on any
|
|
111
111
|
#: change, so bumping a module forces a decision about this one.
|
|
112
|
-
__dist_version__ = "3.
|
|
112
|
+
__dist_version__ = "3.23.0"
|
|
113
113
|
|
|
114
114
|
__all__ = [
|
|
115
115
|
"Client",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|