|
15 | 15 | <link rel="canonical" href="https://agentclientprotocol.github.io/python-sdk/contrib/"> |
16 | 16 |
|
17 | 17 |
|
18 | | - <link rel="prev" href="../quickstart/"> |
| 18 | + <link rel="prev" href="../use-cases/"> |
19 | 19 |
|
20 | 20 |
|
21 | 21 | <link rel="next" href="../releasing/"> |
|
303 | 303 |
|
304 | 304 |
|
305 | 305 |
|
| 306 | + |
| 307 | + |
| 308 | + <li class="md-nav__item"> |
| 309 | + <a href="../use-cases/" class="md-nav__link"> |
| 310 | + |
| 311 | + |
| 312 | + |
| 313 | + <span class="md-ellipsis"> |
| 314 | + Use Cases |
| 315 | + |
| 316 | + </span> |
| 317 | + |
| 318 | + |
| 319 | + </a> |
| 320 | + </li> |
| 321 | + |
| 322 | + |
| 323 | + |
| 324 | + |
| 325 | + |
| 326 | + |
| 327 | + |
306 | 328 |
|
307 | 329 |
|
308 | 330 |
|
|
356 | 378 | <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix> |
357 | 379 |
|
358 | 380 | <li class="md-nav__item"> |
359 | | - <a href="#sessionaccumulator" class="md-nav__link"> |
| 381 | + <a href="#sessionaccumulator-acpcontribsession_state" class="md-nav__link"> |
360 | 382 | <span class="md-ellipsis"> |
361 | | - SessionAccumulator |
| 383 | + SessionAccumulator (acp.contrib.session_state) |
362 | 384 | </span> |
363 | 385 | </a> |
364 | 386 |
|
365 | 387 | </li> |
366 | 388 |
|
367 | 389 | <li class="md-nav__item"> |
368 | | - <a href="#toolcalltracker-permissionbroker" class="md-nav__link"> |
| 390 | + <a href="#toolcalltracker-permissionbroker-acpcontribtool_calls-acpcontribpermissions" class="md-nav__link"> |
369 | 391 | <span class="md-ellipsis"> |
370 | | - ToolCallTracker & PermissionBroker |
| 392 | + ToolCallTracker & PermissionBroker (acp.contrib.tool_calls, acp.contrib.permissions) |
371 | 393 | </span> |
372 | 394 | </a> |
373 | 395 |
|
|
439 | 461 | <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix> |
440 | 462 |
|
441 | 463 | <li class="md-nav__item"> |
442 | | - <a href="#sessionaccumulator" class="md-nav__link"> |
| 464 | + <a href="#sessionaccumulator-acpcontribsession_state" class="md-nav__link"> |
443 | 465 | <span class="md-ellipsis"> |
444 | | - SessionAccumulator |
| 466 | + SessionAccumulator (acp.contrib.session_state) |
445 | 467 | </span> |
446 | 468 | </a> |
447 | 469 |
|
448 | 470 | </li> |
449 | 471 |
|
450 | 472 | <li class="md-nav__item"> |
451 | | - <a href="#toolcalltracker-permissionbroker" class="md-nav__link"> |
| 473 | + <a href="#toolcalltracker-permissionbroker-acpcontribtool_calls-acpcontribpermissions" class="md-nav__link"> |
452 | 474 | <span class="md-ellipsis"> |
453 | | - ToolCallTracker & PermissionBroker |
| 475 | + ToolCallTracker & PermissionBroker (acp.contrib.tool_calls, acp.contrib.permissions) |
454 | 476 | </span> |
455 | 477 | </a> |
456 | 478 |
|
|
485 | 507 |
|
486 | 508 |
|
487 | 509 | <h1 id="experimental-contrib-modules">Experimental Contrib Modules<a class="headerlink" href="#experimental-contrib-modules" title="Permanent link">¶</a></h1> |
488 | | -<blockquote> |
489 | | -<p>The helpers under <code>acp.contrib</code> capture patterns we observed in reference integrations such as Toad and kimi-cli. Every API here is experimental and may change without notice.</p> |
490 | | -</blockquote> |
491 | | -<h2 id="sessionaccumulator">SessionAccumulator<a class="headerlink" href="#sessionaccumulator" title="Permanent link">¶</a></h2> |
492 | | -<p>Module: <code>acp.contrib.session_state</code></p> |
493 | | -<p>UI surfaces like Toad need a live, merged view of the latest tool calls, plan entries, and message stream. The core SDK only emits raw <code>SessionNotification</code> payloads, so applications usually end up writing their own state layer. <code>SessionAccumulator</code> offers that cache out of the box.</p> |
494 | | -<p>Capabilities:</p> |
| 510 | +<p>The helpers under <code>acp.contrib</code> package recurring patterns we saw in integrations such as Toad, kimi-cli, and Gemini. Keep in mind they are experimental—APIs can still shift as we learn. Use this page as a menu:</p> |
| 511 | +<ul> |
| 512 | +<li><strong><code>session_state.SessionAccumulator</code></strong> — build a canonical, immutable snapshot of every session update so UIs can render tool calls and plans without re-implementing state machines.</li> |
| 513 | +<li><strong><code>tool_calls.ToolCallTracker</code> + <code>permissions.PermissionBroker</code></strong> — coordinate streamed tool call updates and permission prompts from one place.</li> |
| 514 | +</ul> |
| 515 | +<h2 id="sessionaccumulator-acpcontribsession_state">SessionAccumulator (<code>acp.contrib.session_state</code>)<a class="headerlink" href="#sessionaccumulator-acpcontribsession_state" title="Permanent link">¶</a></h2> |
| 516 | +<p><strong>Use it when:</strong> you need a live, merged view of <code>SessionNotification</code> events (e.g. tool calls, plan entries, user/agent messages) to drive UI widgets.</p> |
| 517 | +<p><strong>Key capabilities</strong></p> |
495 | 518 | <ul> |
496 | | -<li><code>SessionAccumulator.apply(notification)</code> merges <code>tool_call</code> and <code>tool_call_update</code> events, backfilling a missing start message when necessary.</li> |
497 | | -<li>Each call to <code>snapshot()</code> returns an immutable <code>SessionSnapshot</code> (Pydantic model) containing the active plan, current mode ID, available commands, and historical user/agent/thought chunks.</li> |
498 | | -<li><code>subscribe(callback)</code> wires a lightweight observer that receives every new snapshot, making it easy to refresh UI widgets.</li> |
499 | | -<li>Automatic reset when a different session ID arrives (configurable via <code>auto_reset_on_session_change</code>).</li> |
| 519 | +<li><code>SessionAccumulator.apply(notification)</code> reconciles <code>tool_call</code> and <code>tool_call_update</code> payloads, even if the start event arrives late.</li> |
| 520 | +<li><code>snapshot()</code> returns an immutable <code>SessionSnapshot</code> Pydantic model containing the plan, current mode, commands, and ordered message history.</li> |
| 521 | +<li><code>subscribe(callback)</code> lets you push snapshots into stores or UI components whenever state changes.</li> |
| 522 | +<li>Automatic reset on session-change (toggle with <code>auto_reset_on_session_change</code>).</li> |
500 | 523 | </ul> |
501 | 524 | <blockquote> |
502 | | -<p>Integration tip: create one accumulator per UI controller. Feed every <code>SessionNotification</code> through it, then render from <code>snapshot.tool_calls</code> or <code>snapshot.user_messages</code> instead of mutating state manually.</p> |
| 525 | +<p>Tip: Create one accumulator per UI controller. Feed every raw <code>SessionNotification</code> into it and render from <code>snapshot.tool_calls</code> / <code>snapshot.user_messages</code> instead of mutating state manually.</p> |
503 | 526 | </blockquote> |
504 | | -<h2 id="toolcalltracker-permissionbroker">ToolCallTracker & PermissionBroker<a class="headerlink" href="#toolcalltracker-permissionbroker" title="Permanent link">¶</a></h2> |
505 | | -<p>Modules: <code>acp.contrib.tool_calls</code> and <code>acp.contrib.permissions</code></p> |
506 | | -<p>Agent-side runtimes (for example kimi-cli) are responsible for synthesising tool call IDs, streaming argument fragments, and formatting permission prompts. Managing bare Pydantic models quickly devolves into boilerplate; these helpers centralise the bookkeeping.</p> |
| 527 | +<h2 id="toolcalltracker-permissionbroker-acpcontribtool_calls-acpcontribpermissions">ToolCallTracker & PermissionBroker (<code>acp.contrib.tool_calls</code>, <code>acp.contrib.permissions</code>)<a class="headerlink" href="#toolcalltracker-permissionbroker-acpcontribtool_calls-acpcontribpermissions" title="Permanent link">¶</a></h2> |
| 528 | +<p><strong>Use them when:</strong> your agent runtime synthesises tool call IDs, streams arguments, and prompts the user for approval. The helpers centralise the bookkeeping so you don’t juggle raw Pydantic models.</p> |
507 | 529 | <ul> |
508 | | -<li><code>ToolCallTracker.start()/progress()/append_stream_text()</code> manages tool call state and emits canonical <code>ToolCallStart</code> / <code>ToolCallProgress</code> messages. The tracker also exposes <code>view()</code> (immutable <code>TrackedToolCallView</code>) and <code>tool_call_model()</code> for logging or permission prompts.</li> |
509 | | -<li><code>PermissionBroker.request_for()</code> wraps <code>requestPermission</code> RPCs. It reuses the tracker’s state (or an explicit <code>ToolCall</code>), applies optional extra content, and defaults to a standard Approve / Approve for session / Reject option set.</li> |
510 | | -<li><code>default_permission_options()</code> exposes that canonical option triple so applications can customise or extend it.</li> |
| 530 | +<li><code>ToolCallTracker.start()/progress()/append_stream_text()</code> emits canonical <code>ToolCallStart</code> / <code>ToolCallProgress</code> updates and keeps an in-memory view via <code>view()</code> or <code>tool_call_model()</code>.</li> |
| 531 | +<li><code>PermissionBroker.request_for()</code> wraps <code>requestPermission</code> RPCs. It reuses tracker state (or a provided <code>ToolCall</code>), lets you append extra content, and defaults to Approve / Approve for session / Reject options.</li> |
| 532 | +<li><code>default_permission_options()</code> exposes that canonical option triple if you need to customise it.</li> |
511 | 533 | </ul> |
512 | 534 | <blockquote> |
513 | | -<p>Integration tip: keep a single tracker alongside your agent loop. Emit tool call notifications through it, and hand the tracker to <code>PermissionBroker</code> so permission prompts stay in sync with the latest call state.</p> |
| 535 | +<p>Tip: Keep one tracker near the agent event loop. Emit notifications through it and share the tracker with <code>PermissionBroker</code> so permission prompts always match the latest tool call state.</p> |
514 | 536 | </blockquote> |
515 | 537 | <h2 id="design-guardrails">Design Guardrails<a class="headerlink" href="#design-guardrails" title="Permanent link">¶</a></h2> |
516 | 538 | <p>To stay aligned with the ACP schema, the contrib layer follows a few rules:</p> |
517 | 539 | <ul> |
518 | | -<li>Protocol types continue to live in <code>acp.schema</code>. Contrib code always copies them via <code>.model_copy(deep=True)</code> to avoid mutating shared instances.</li> |
519 | | -<li>Helpers are opt-in; the core package never imports them implicitly and imposes no UI or agent framework assumptions.</li> |
520 | | -<li>Implementations focus on the common pain points (tool call aggregation, permission requests) while leaving business-specific policy to the application.</li> |
| 540 | +<li>Schema data classes continue to live in <code>acp.schema</code>. Contrib helpers clone them with <code>.model_copy(deep=True)</code> before mutation.</li> |
| 541 | +<li>The core runtime never imports contrib modules implicitly—you opt in when they help.</li> |
| 542 | +<li>Helpers focus on painful bookkeeping (tool call aggregation, permission UX) and leave product-specific policy to your application.</li> |
521 | 543 | </ul> |
522 | | -<p>Try the contrib modules in your agent or client, and open an issue/PR with feedback so we can decide which pieces should graduate into the stable surface.</p> |
| 544 | +<p>Try the contrib modules, then open an issue or PR with feedback so we know which APIs should graduate into the stable surface.</p> |
523 | 545 |
|
524 | 546 |
|
525 | 547 |
|
|
0 commit comments