agenthooksprotocol 0.2.0__tar.gz → 0.3.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.
- {agenthooksprotocol-0.2.0/src/agenthooksprotocol.egg-info → agenthooksprotocol-0.3.0}/PKG-INFO +106 -66
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/README.md +105 -65
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/pyproject.toml +1 -1
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_boundaries.py +66 -49
- agenthooksprotocol-0.3.0/src/agenthooksprotocol/_content.py +884 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_hooks.py +277 -18
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/__init__.py +12248 -13693
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/content.py +2 -28
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/event.py +4 -4
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/tool.py +2 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/ahp-codegen.lock.json +8 -8
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/attachment.py +6 -1
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/compaction.py +69 -56
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/content.py +1 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/effect.py +2 -1
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/elicitation.py +12 -12
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/event.py +2 -2
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/generated.py +262 -554
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/interop.py +83 -39
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/lifecycle.py +5 -12
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/lifecycle_client.py +5 -2
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/lineage.py +15 -25
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/runtime.py +75 -32
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/schemas.json +421 -127
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/tool.py +1 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0/src/agenthooksprotocol.egg-info}/PKG-INFO +106 -66
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol.egg-info/SOURCES.txt +5 -1
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_attachments.py +279 -277
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_catalogue.py +27 -12
- agenthooksprotocol-0.3.0/tests/test_compaction.py +393 -0
- agenthooksprotocol-0.3.0/tests/test_compaction_wire.py +259 -0
- agenthooksprotocol-0.3.0/tests/test_content_lifetime.py +393 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_content_receipts.py +14 -6
- agenthooksprotocol-0.3.0/tests/test_elicitation_adapter.py +83 -0
- agenthooksprotocol-0.3.0/tests/test_inline_messages.py +983 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_integration.py +51 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_integration_edges.py +15 -15
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_interop.py +74 -18
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_lifecycle.py +4 -4
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_lifecycle_auth.py +3 -3
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_owned_content.py +76 -42
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_owned_content_hooks.py +54 -51
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_public_content.py +195 -204
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_public_hooks.py +59 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_schema_corrections.py +37 -8
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_sdk_unification.py +10 -5
- agenthooksprotocol-0.3.0/tests/test_shared_materialization.py +389 -0
- agenthooksprotocol-0.3.0/tests/test_upload_planning.py +361 -0
- agenthooksprotocol-0.2.0/src/agenthooksprotocol/_content.py +0 -801
- agenthooksprotocol-0.2.0/tests/test_compaction.py +0 -199
- agenthooksprotocol-0.2.0/tests/test_compaction_wire.py +0 -73
- agenthooksprotocol-0.2.0/tests/test_content_lifetime.py +0 -315
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/LICENSE +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/setup.cfg +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/__init__.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_diagnostics.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_grants.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/capability.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/effect.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/registration.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/subscription.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/_models/transport.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/auth.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/candidate.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/capability.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/catalogue.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/codec.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/diagnostics.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/integrations/__init__.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/integrations/pydantic.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/lifecycle_server.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/observation_chain.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/path.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/permission.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/py.typed +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/registration.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/server/__init__.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/server/_framing.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/server/_json.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/server/asgi.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/server/attachments.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/server/hooks.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/server/stdio.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/state.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/subscription.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/transport.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/transports/__init__.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/transports/http.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol/transports/stdio.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol.egg-info/dependency_links.txt +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol.egg-info/requires.txt +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/src/agenthooksprotocol.egg-info/top_level.txt +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_codec.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_content.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_fixture_public.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_observation.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_observation_chain_transport.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_package.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_public_examples.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_public_server.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_registration_auth.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_safety.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_session_manifest.py +0 -0
- {agenthooksprotocol-0.2.0 → agenthooksprotocol-0.3.0}/tests/test_structural_facade.py +0 -0
{agenthooksprotocol-0.2.0/src/agenthooksprotocol.egg-info → agenthooksprotocol-0.3.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agenthooksprotocol
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Official non-normative Python SDK for the Agent Hooks Protocol
|
|
5
5
|
Author: Agent Hooks Protocol maintainers
|
|
6
6
|
License:
|
|
@@ -327,30 +327,63 @@ Observation is one-way. It does not acquire effect authority and never waits for
|
|
|
327
327
|
|
|
328
328
|
The attachment receiver verifies byte length and digest through EOF before committing caller-provided immutable storage. Receiver-allocated references are published only after authorization and successful storage commit. Applications choose storage durability and retention.
|
|
329
329
|
|
|
330
|
-
##
|
|
330
|
+
## Inline messages and specialized boundaries
|
|
331
331
|
|
|
332
|
-
|
|
332
|
+
Model-visible inputs contain canonical messages with a `role` and ordered
|
|
333
|
+
`parts`. Supported roles are `system`, `developer`, `user`, `assistant`, and
|
|
334
|
+
`tool`. A text part has `kind="text"`, `mediaType="text/plain"`, and inline
|
|
335
|
+
`text`. Serialized JSON is ordinary text. An attachment part has
|
|
336
|
+
`kind="attachment"`, a non-text/non-JSON media type, and an immutable binary
|
|
337
|
+
body. Construction supplies missing message/part IDs and marks them
|
|
338
|
+
`synthesized=True`; explicit IDs remain stable.
|
|
333
339
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
Pass the bound input to a named hook method with `uploads={backend_id: authorized_upload_callback}`. Each callback receives immutable bytes and returns a receiver-allocated canonical upload receipt; it can use `auth.AuthenticatedHTTPTransport.upload(..., authentication=upload_binding)`. Metadata, omit, and unmatched receivers consume no bytes and require no uploader. Selected body delivery snapshots once within limits, hashes actual raw bytes, uploads independently for each authorized destination, and verifies receipts before event delivery. Missing receiver authorization fails before reading. Use `ContentSources` to supply explicit source bindings, or `ContentContext` to resolve canonical references.
|
|
350
|
-
|
|
351
|
-
Ownership transfers to the source wrapper, then to the hook operation when passed. Streams close on success, failure, cancellation, and unused selection; snapshots release when the call finishes. Closed wrappers also release their reader, so retaining a source or result does not retain the reader’s input buffer. Sources are single-operation values, not concurrently reusable. Call `aclose()` or use an async context manager for a source that never reaches a hook call. Cleanup is shielded and bounded separately from the operation budget.
|
|
340
|
+
```python
|
|
341
|
+
from agenthooksprotocol import Attachment
|
|
342
|
+
|
|
343
|
+
input = {
|
|
344
|
+
"trigger": "manual",
|
|
345
|
+
"items": [{"role": "user", "parts": [
|
|
346
|
+
{"kind": "text", "text": "Review this report."},
|
|
347
|
+
{"kind": "attachment", "mediaType": "application/pdf",
|
|
348
|
+
"body": Attachment.from_bytes(pdf_bytes)},
|
|
349
|
+
]}],
|
|
350
|
+
}
|
|
351
|
+
result = await hooks.context_compact_before(input, uploads=authorized_uploads)
|
|
352
|
+
async with result:
|
|
353
|
+
data = await result.attachments.read("context.compact.before.items_parts[0][1]")
|
|
354
|
+
```
|
|
352
355
|
|
|
353
|
-
|
|
356
|
+
Named hook methods also accept canonical dictionaries with the same direct
|
|
357
|
+
attachment bodies. The runtime collects sources and creates receiver-specific
|
|
358
|
+
references internally. Construction and metadata/omit projection do not read
|
|
359
|
+
or upload attachments. Only schema-owned slots are projected; native payloads,
|
|
360
|
+
extensions, and application arguments are opaque. Selection is a ceiling for
|
|
361
|
+
each receiver's view: metadata/omit views contain no inline text or attachment
|
|
362
|
+
references. Independent receivers apply their own content selections.
|
|
363
|
+
|
|
364
|
+
Compaction `instructions` and `summary` are canonical text-part lists.
|
|
365
|
+
Replacement substitutes the list; merge appends in order. Model-visible message
|
|
366
|
+
list targets (`prompt`, `request`, `response`, and tool `output`) have the same
|
|
367
|
+
list operations. Tool output edits operate on `tool.after.items`; application
|
|
368
|
+
structures are serialized as text parts. Standalone `content` edits require the
|
|
369
|
+
boundary context: `user.message.outbound` uses a message list, and accepted form
|
|
370
|
+
answers at `user.elicitation.result` use an MCP answer object. Object targets such as tool input and workspace changes use shallow object merge. A response settles
|
|
371
|
+
atomically, and each serial receiver sees the committed state. Changed
|
|
372
|
+
compaction instructions invalidate an earlier supplied summary.
|
|
373
|
+
|
|
374
|
+
MCP elicitation `request` and `result` contain selected text parts whose `text`
|
|
375
|
+
is the serialized complete MCP JSON payload. The SDK validates parsed payloads,
|
|
376
|
+
mode grants, form answers, and correlation without inserting defaults. Result
|
|
377
|
+
edits require `original_request=` with the original canonical intercept request
|
|
378
|
+
snapshot; answer-object merge is shallow. Elicitation request bodies are immutable
|
|
379
|
+
to modification effects. No text/JSON upload callback is needed. Metadata and omit selections
|
|
380
|
+
cannot authorize body-dependent effects.
|
|
381
|
+
|
|
382
|
+
For custom transports, `begin(canonical_request)` separates acquisition,
|
|
383
|
+
cancellation, and acceptance; `exchange(canonical_request)` uses the same
|
|
384
|
+
settlement engine. Elicitation correlation can be supplied through
|
|
385
|
+
`ContentContext(original_request=..., bindings={"content": ("elicitation", "result")},
|
|
386
|
+
principal=authenticated_identity)` and `await pending.accept_content()`.
|
|
354
387
|
|
|
355
388
|
## Generated models and provenance
|
|
356
389
|
|
|
@@ -374,7 +407,7 @@ Integration tests also use a matching sibling `../agent-hooks-protocol` checkout
|
|
|
374
407
|
Generated facade constructors retain nested model types through schema
|
|
375
408
|
compositions. MCP connection `gaps` parameters accept lists of typed gap models,
|
|
376
409
|
and HTTP, SSE, stdio, and custom connection objects expose typed location and gap
|
|
377
|
-
attributes. `ModelVisibleItem`
|
|
410
|
+
attributes. `ModelVisibleItem` is a canonical message with a typed role and ordered parts.
|
|
378
411
|
|
|
379
412
|
Facade objects are mappings with read-only attributes.
|
|
380
413
|
Optional attributes return `None` when absent; mapping membership still records
|
|
@@ -454,48 +487,55 @@ keys such as `toolName` and `tool_name` remain distinct wire/extension keys.
|
|
|
454
487
|
|
|
455
488
|
### Owned attachments
|
|
456
489
|
|
|
457
|
-
The owned attachment APIs in this section are not included in the published 0.1.1 package.
|
|
458
|
-
|
|
459
490
|
Use `Attachment.from_bytes(data)` for immutable Python `bytes`, or
|
|
460
|
-
`Attachment.lazy(async_loader, aclose=async_cleanup)` to defer reading.
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
491
|
+
`Attachment.lazy(async_loader, aclose=async_cleanup)` to defer reading. Put
|
|
492
|
+
`attachment` directly in an attachment part's `body`. Named `Hooks` methods
|
|
493
|
+
accept both dictionary inputs and typed event inputs with the same owner.
|
|
494
|
+
Metadata belongs on the part. See the runnable
|
|
495
|
+
[file attachment example](examples/file_attachment.py).
|
|
496
|
+
|
|
497
|
+
Dispatch transfers ownership once. Successful results retain the exact owner,
|
|
498
|
+
including an unread loader, independently of `Hooks` shutdown. Callers close
|
|
499
|
+
returned content owners with `async with result:` or `await result.aclose()`.
|
|
500
|
+
Cleanup runs for unopened sources too. Create a new attachment for each
|
|
501
|
+
invocation; eager attachments can share the same immutable `bytes` object.
|
|
502
|
+
|
|
503
|
+
The default accepted size is 4 MiB and lazy loading timeout is 30 seconds.
|
|
504
|
+
Constructors accept `max_bytes`; lazy construction accepts `timeout`. Loaders
|
|
505
|
+
must bound their own allocations. `Attachment(async_stream, ...)` supports
|
|
506
|
+
bounded `read(size)`/`receive(max_bytes)` streams. Stream cleanup is shielded and
|
|
507
|
+
bounded to one second. Cancellation and failure never retry a loader. Mutable
|
|
508
|
+
buffers are rejected, and reads return immutable bytes.
|
|
509
|
+
|
|
510
|
+
Selected remote binary delivery requires an authorized uploader through
|
|
511
|
+
`uploads={backend_id: async_upload}`. Each uploader receives the exact owner's
|
|
512
|
+
immutable bytes and returns a committed receipt with `ref`, `size`, and `sha256`.
|
|
513
|
+
The SDK validates the receipt against the actual bytes before sending the event.
|
|
514
|
+
Upload callbacks remain caller-authorized and scoped to their backend; event
|
|
515
|
+
credentials do not authorize uploads to another destination.
|
|
516
|
+
|
|
517
|
+
`Hooks(..., max_concurrent_uploads=8)` bounds concurrent binary uploads.
|
|
518
|
+
The value must be a positive integer. Before serial interception
|
|
519
|
+
begins, the SDK prepares uploads for body-selected attachment slots in all
|
|
520
|
+
matched subscriptions, including observers. One attachment owner is read once
|
|
521
|
+
for multiple subscribers. Metadata, omit, and unmatched selections do not read
|
|
522
|
+
or upload its bytes. Result reads and metadata-only delivery require no uploader.
|
|
523
|
+
|
|
524
|
+
Only confirmed receipts are cached, for the exact attachment owner and backend
|
|
525
|
+
ID/subscription index. An uncalled interceptor receives a settled observation
|
|
526
|
+
with its cached reference after denial or stop. Upload failures are handled by
|
|
527
|
+
the affected subscription's failure policy when its delivery is reached; they
|
|
528
|
+
do not prevent independent destinations from preparing their uploads. An upload
|
|
529
|
+
can commit even if an earlier interceptor later removes the attachment or halts
|
|
530
|
+
the chain. Receiver applications manage separate storage durability and retention.
|
|
531
|
+
Cancellation cancels and joins pending upload work and closes invocation-owned
|
|
532
|
+
sources. Overlapping reads join one materialization and receive the same immutable
|
|
533
|
+
bytes or terminal error. Cancelling one reader leaves materialization active for
|
|
534
|
+
other readers; the last cancelled reader or owner closure cancels and joins it.
|
|
535
|
+
The attachment owns its single pending materialization independently of readers.
|
|
536
|
+
A cancelled reader returns and releases its upload permit while another reader
|
|
537
|
+
continues. The last reader or owner closure joins cleanup; completed workers are
|
|
538
|
+
not retained.
|
|
539
|
+
|
|
540
|
+
Attachments are the sole byte owners. Binary/file editing is not supported.
|
|
501
541
|
Results are invocation-local, not session archives.
|
|
@@ -103,30 +103,63 @@ Observation is one-way. It does not acquire effect authority and never waits for
|
|
|
103
103
|
|
|
104
104
|
The attachment receiver verifies byte length and digest through EOF before committing caller-provided immutable storage. Receiver-allocated references are published only after authorization and successful storage commit. Applications choose storage durability and retention.
|
|
105
105
|
|
|
106
|
-
##
|
|
106
|
+
## Inline messages and specialized boundaries
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
Model-visible inputs contain canonical messages with a `role` and ordered
|
|
109
|
+
`parts`. Supported roles are `system`, `developer`, `user`, `assistant`, and
|
|
110
|
+
`tool`. A text part has `kind="text"`, `mediaType="text/plain"`, and inline
|
|
111
|
+
`text`. Serialized JSON is ordinary text. An attachment part has
|
|
112
|
+
`kind="attachment"`, a non-text/non-JSON media type, and an immutable binary
|
|
113
|
+
body. Construction supplies missing message/part IDs and marks them
|
|
114
|
+
`synthesized=True`; explicit IDs remain stable.
|
|
109
115
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
Pass the bound input to a named hook method with `uploads={backend_id: authorized_upload_callback}`. Each callback receives immutable bytes and returns a receiver-allocated canonical upload receipt; it can use `auth.AuthenticatedHTTPTransport.upload(..., authentication=upload_binding)`. Metadata, omit, and unmatched receivers consume no bytes and require no uploader. Selected body delivery snapshots once within limits, hashes actual raw bytes, uploads independently for each authorized destination, and verifies receipts before event delivery. Missing receiver authorization fails before reading. Use `ContentSources` to supply explicit source bindings, or `ContentContext` to resolve canonical references.
|
|
126
|
-
|
|
127
|
-
Ownership transfers to the source wrapper, then to the hook operation when passed. Streams close on success, failure, cancellation, and unused selection; snapshots release when the call finishes. Closed wrappers also release their reader, so retaining a source or result does not retain the reader’s input buffer. Sources are single-operation values, not concurrently reusable. Call `aclose()` or use an async context manager for a source that never reaches a hook call. Cleanup is shielded and bounded separately from the operation budget.
|
|
116
|
+
```python
|
|
117
|
+
from agenthooksprotocol import Attachment
|
|
118
|
+
|
|
119
|
+
input = {
|
|
120
|
+
"trigger": "manual",
|
|
121
|
+
"items": [{"role": "user", "parts": [
|
|
122
|
+
{"kind": "text", "text": "Review this report."},
|
|
123
|
+
{"kind": "attachment", "mediaType": "application/pdf",
|
|
124
|
+
"body": Attachment.from_bytes(pdf_bytes)},
|
|
125
|
+
]}],
|
|
126
|
+
}
|
|
127
|
+
result = await hooks.context_compact_before(input, uploads=authorized_uploads)
|
|
128
|
+
async with result:
|
|
129
|
+
data = await result.attachments.read("context.compact.before.items_parts[0][1]")
|
|
130
|
+
```
|
|
128
131
|
|
|
129
|
-
|
|
132
|
+
Named hook methods also accept canonical dictionaries with the same direct
|
|
133
|
+
attachment bodies. The runtime collects sources and creates receiver-specific
|
|
134
|
+
references internally. Construction and metadata/omit projection do not read
|
|
135
|
+
or upload attachments. Only schema-owned slots are projected; native payloads,
|
|
136
|
+
extensions, and application arguments are opaque. Selection is a ceiling for
|
|
137
|
+
each receiver's view: metadata/omit views contain no inline text or attachment
|
|
138
|
+
references. Independent receivers apply their own content selections.
|
|
139
|
+
|
|
140
|
+
Compaction `instructions` and `summary` are canonical text-part lists.
|
|
141
|
+
Replacement substitutes the list; merge appends in order. Model-visible message
|
|
142
|
+
list targets (`prompt`, `request`, `response`, and tool `output`) have the same
|
|
143
|
+
list operations. Tool output edits operate on `tool.after.items`; application
|
|
144
|
+
structures are serialized as text parts. Standalone `content` edits require the
|
|
145
|
+
boundary context: `user.message.outbound` uses a message list, and accepted form
|
|
146
|
+
answers at `user.elicitation.result` use an MCP answer object. Object targets such as tool input and workspace changes use shallow object merge. A response settles
|
|
147
|
+
atomically, and each serial receiver sees the committed state. Changed
|
|
148
|
+
compaction instructions invalidate an earlier supplied summary.
|
|
149
|
+
|
|
150
|
+
MCP elicitation `request` and `result` contain selected text parts whose `text`
|
|
151
|
+
is the serialized complete MCP JSON payload. The SDK validates parsed payloads,
|
|
152
|
+
mode grants, form answers, and correlation without inserting defaults. Result
|
|
153
|
+
edits require `original_request=` with the original canonical intercept request
|
|
154
|
+
snapshot; answer-object merge is shallow. Elicitation request bodies are immutable
|
|
155
|
+
to modification effects. No text/JSON upload callback is needed. Metadata and omit selections
|
|
156
|
+
cannot authorize body-dependent effects.
|
|
157
|
+
|
|
158
|
+
For custom transports, `begin(canonical_request)` separates acquisition,
|
|
159
|
+
cancellation, and acceptance; `exchange(canonical_request)` uses the same
|
|
160
|
+
settlement engine. Elicitation correlation can be supplied through
|
|
161
|
+
`ContentContext(original_request=..., bindings={"content": ("elicitation", "result")},
|
|
162
|
+
principal=authenticated_identity)` and `await pending.accept_content()`.
|
|
130
163
|
|
|
131
164
|
## Generated models and provenance
|
|
132
165
|
|
|
@@ -150,7 +183,7 @@ Integration tests also use a matching sibling `../agent-hooks-protocol` checkout
|
|
|
150
183
|
Generated facade constructors retain nested model types through schema
|
|
151
184
|
compositions. MCP connection `gaps` parameters accept lists of typed gap models,
|
|
152
185
|
and HTTP, SSE, stdio, and custom connection objects expose typed location and gap
|
|
153
|
-
attributes. `ModelVisibleItem`
|
|
186
|
+
attributes. `ModelVisibleItem` is a canonical message with a typed role and ordered parts.
|
|
154
187
|
|
|
155
188
|
Facade objects are mappings with read-only attributes.
|
|
156
189
|
Optional attributes return `None` when absent; mapping membership still records
|
|
@@ -230,48 +263,55 @@ keys such as `toolName` and `tool_name` remain distinct wire/extension keys.
|
|
|
230
263
|
|
|
231
264
|
### Owned attachments
|
|
232
265
|
|
|
233
|
-
The owned attachment APIs in this section are not included in the published 0.1.1 package.
|
|
234
|
-
|
|
235
266
|
Use `Attachment.from_bytes(data)` for immutable Python `bytes`, or
|
|
236
|
-
`Attachment.lazy(async_loader, aclose=async_cleanup)` to defer reading.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
267
|
+
`Attachment.lazy(async_loader, aclose=async_cleanup)` to defer reading. Put
|
|
268
|
+
`attachment` directly in an attachment part's `body`. Named `Hooks` methods
|
|
269
|
+
accept both dictionary inputs and typed event inputs with the same owner.
|
|
270
|
+
Metadata belongs on the part. See the runnable
|
|
271
|
+
[file attachment example](examples/file_attachment.py).
|
|
272
|
+
|
|
273
|
+
Dispatch transfers ownership once. Successful results retain the exact owner,
|
|
274
|
+
including an unread loader, independently of `Hooks` shutdown. Callers close
|
|
275
|
+
returned content owners with `async with result:` or `await result.aclose()`.
|
|
276
|
+
Cleanup runs for unopened sources too. Create a new attachment for each
|
|
277
|
+
invocation; eager attachments can share the same immutable `bytes` object.
|
|
278
|
+
|
|
279
|
+
The default accepted size is 4 MiB and lazy loading timeout is 30 seconds.
|
|
280
|
+
Constructors accept `max_bytes`; lazy construction accepts `timeout`. Loaders
|
|
281
|
+
must bound their own allocations. `Attachment(async_stream, ...)` supports
|
|
282
|
+
bounded `read(size)`/`receive(max_bytes)` streams. Stream cleanup is shielded and
|
|
283
|
+
bounded to one second. Cancellation and failure never retry a loader. Mutable
|
|
284
|
+
buffers are rejected, and reads return immutable bytes.
|
|
285
|
+
|
|
286
|
+
Selected remote binary delivery requires an authorized uploader through
|
|
287
|
+
`uploads={backend_id: async_upload}`. Each uploader receives the exact owner's
|
|
288
|
+
immutable bytes and returns a committed receipt with `ref`, `size`, and `sha256`.
|
|
289
|
+
The SDK validates the receipt against the actual bytes before sending the event.
|
|
290
|
+
Upload callbacks remain caller-authorized and scoped to their backend; event
|
|
291
|
+
credentials do not authorize uploads to another destination.
|
|
292
|
+
|
|
293
|
+
`Hooks(..., max_concurrent_uploads=8)` bounds concurrent binary uploads.
|
|
294
|
+
The value must be a positive integer. Before serial interception
|
|
295
|
+
begins, the SDK prepares uploads for body-selected attachment slots in all
|
|
296
|
+
matched subscriptions, including observers. One attachment owner is read once
|
|
297
|
+
for multiple subscribers. Metadata, omit, and unmatched selections do not read
|
|
298
|
+
or upload its bytes. Result reads and metadata-only delivery require no uploader.
|
|
299
|
+
|
|
300
|
+
Only confirmed receipts are cached, for the exact attachment owner and backend
|
|
301
|
+
ID/subscription index. An uncalled interceptor receives a settled observation
|
|
302
|
+
with its cached reference after denial or stop. Upload failures are handled by
|
|
303
|
+
the affected subscription's failure policy when its delivery is reached; they
|
|
304
|
+
do not prevent independent destinations from preparing their uploads. An upload
|
|
305
|
+
can commit even if an earlier interceptor later removes the attachment or halts
|
|
306
|
+
the chain. Receiver applications manage separate storage durability and retention.
|
|
307
|
+
Cancellation cancels and joins pending upload work and closes invocation-owned
|
|
308
|
+
sources. Overlapping reads join one materialization and receive the same immutable
|
|
309
|
+
bytes or terminal error. Cancelling one reader leaves materialization active for
|
|
310
|
+
other readers; the last cancelled reader or owner closure cancels and joins it.
|
|
311
|
+
The attachment owns its single pending materialization independently of readers.
|
|
312
|
+
A cancelled reader returns and releases its upload permit while another reader
|
|
313
|
+
continues. The last reader or owner closure joins cleanup; completed workers are
|
|
314
|
+
not retained.
|
|
315
|
+
|
|
316
|
+
Attachments are the sole byte owners. Binary/file editing is not supported.
|
|
277
317
|
Results are invocation-local, not session archives.
|