@pi-in-go/pigpen-ahp 0.1.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.
- package/CREDITS.md +27 -0
- package/LICENSE +23 -0
- package/README.md +148 -0
- package/extensions/ahp/access_options_test.go +116 -0
- package/extensions/ahp/extension.go +54 -0
- package/extensions/ahp/go.mod +12 -0
- package/extensions/ahp/go.sum +2 -0
- package/extensions/ahp/go.work +8 -0
- package/extensions/ahp/internal/channels/chat.go +110 -0
- package/extensions/ahp/internal/channels/root.go +32 -0
- package/extensions/ahp/internal/channels/session.go +128 -0
- package/extensions/ahp/internal/channels/session_test.go +108 -0
- package/extensions/ahp/internal/compose/compose.go +153 -0
- package/extensions/ahp/internal/compose/compose_test.go +120 -0
- package/extensions/ahp/internal/gaps/gaps_test.go +88 -0
- package/extensions/ahp/internal/host/handshake_test.go +206 -0
- package/extensions/ahp/internal/host/host.go +1305 -0
- package/extensions/ahp/internal/host/reconnect_test.go +197 -0
- package/extensions/ahp/internal/host/replaywindow_test.go +31 -0
- package/extensions/ahp/internal/host/schema_test.go +79 -0
- package/extensions/ahp/internal/host/store.go +291 -0
- package/extensions/ahp/internal/host/store_update_test.go +85 -0
- package/extensions/ahp/internal/host/subscriptions_test.go +160 -0
- package/extensions/ahp/internal/host/surface_test.go +95 -0
- package/extensions/ahp/internal/host/workarounds.go +458 -0
- package/extensions/ahp/internal/host/workarounds_test.go +96 -0
- package/extensions/ahp/internal/live/live.go +328 -0
- package/extensions/ahp/internal/live/live_test.go +91 -0
- package/extensions/ahp/internal/live/store.go +113 -0
- package/extensions/ahp/internal/mapper/activity.go +199 -0
- package/extensions/ahp/internal/mapper/activity_test.go +188 -0
- package/extensions/ahp/internal/mapper/bench_test.go +38 -0
- package/extensions/ahp/internal/mapper/event_mapper_test.go +380 -0
- package/extensions/ahp/internal/mapper/fixtures_test.go +387 -0
- package/extensions/ahp/internal/mapper/helpers_test.go +251 -0
- package/extensions/ahp/internal/mapper/js.go +131 -0
- package/extensions/ahp/internal/mapper/mapper.go +600 -0
- package/extensions/ahp/internal/mapper/message_input_test.go +196 -0
- package/extensions/ahp/internal/mapper/messageinput.go +272 -0
- package/extensions/ahp/internal/mapper/schema_helpers_test.go +5 -0
- package/extensions/ahp/internal/mapper/testdata/LICENSE-pi-ahp +21 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/abort.json +711 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/bash-long-output.json +1312 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/compaction.json +6285 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/parallel-tools.json +2622 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/plain-text.json +1856 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/single-tool.json +1128 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/steering.json +3926 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-bash.json +2372 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-edit.json +3983 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-error.json +2850 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-find.json +1162 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-grep.json +2783 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-loop.json +1693 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-ls.json +2427 -0
- package/extensions/ahp/internal/mapper/testdata/fixtures/tool-write.json +1271 -0
- package/extensions/ahp/internal/mapper/title.go +34 -0
- package/extensions/ahp/internal/mapper/usermsg.go +87 -0
- package/extensions/ahp/internal/pi/activeturn_test.go +296 -0
- package/extensions/ahp/internal/pi/backend.go +64 -0
- package/extensions/ahp/internal/pi/catalogue.go +370 -0
- package/extensions/ahp/internal/pi/catalogue_test.go +271 -0
- package/extensions/ahp/internal/pi/chatdriver.go +533 -0
- package/extensions/ahp/internal/pi/chatdriver_test.go +416 -0
- package/extensions/ahp/internal/pi/clientactions.go +212 -0
- package/extensions/ahp/internal/pi/clientactions_test.go +273 -0
- package/extensions/ahp/internal/pi/completions.go +230 -0
- package/extensions/ahp/internal/pi/completions_test.go +272 -0
- package/extensions/ahp/internal/pi/config_test.go +269 -0
- package/extensions/ahp/internal/pi/deletesession.go +69 -0
- package/extensions/ahp/internal/pi/deletesession_test.go +153 -0
- package/extensions/ahp/internal/pi/disposal_test.go +362 -0
- package/extensions/ahp/internal/pi/fixture_test.go +308 -0
- package/extensions/ahp/internal/pi/foreign_test.go +122 -0
- package/extensions/ahp/internal/pi/harness_test.go +83 -0
- package/extensions/ahp/internal/pi/history.go +269 -0
- package/extensions/ahp/internal/pi/hydrated_test.go +171 -0
- package/extensions/ahp/internal/pi/hydratedlifecycle_test.go +196 -0
- package/extensions/ahp/internal/pi/hydration_test.go +209 -0
- package/extensions/ahp/internal/pi/hydrator.go +212 -0
- package/extensions/ahp/internal/pi/imageinput.go +224 -0
- package/extensions/ahp/internal/pi/imageinput_test.go +57 -0
- package/extensions/ahp/internal/pi/lifecycle_test.go +381 -0
- package/extensions/ahp/internal/pi/models.go +212 -0
- package/extensions/ahp/internal/pi/models_test.go +128 -0
- package/extensions/ahp/internal/pi/paging.go +95 -0
- package/extensions/ahp/internal/pi/pagingtruncate_test.go +323 -0
- package/extensions/ahp/internal/pi/projecttrust.go +222 -0
- package/extensions/ahp/internal/pi/registry.go +924 -0
- package/extensions/ahp/internal/pi/restart_test.go +185 -0
- package/extensions/ahp/internal/pi/services.go +70 -0
- package/extensions/ahp/internal/pi/sessionconfig.go +64 -0
- package/extensions/ahp/internal/pi/sessionfiles_test.go +74 -0
- package/extensions/ahp/internal/pi/sessionstore.go +83 -0
- package/extensions/ahp/internal/pi/summary_test.go +426 -0
- package/extensions/ahp/internal/pi/workarounds_wire_test.go +208 -0
- package/extensions/ahp/internal/pisession/fromentries_test.go +32 -0
- package/extensions/ahp/internal/pisession/json.go +31 -0
- package/extensions/ahp/internal/pisession/pisession.go +580 -0
- package/extensions/ahp/internal/settings/access.go +63 -0
- package/extensions/ahp/internal/settings/access_test.go +52 -0
- package/extensions/ahp/internal/settings/settings.go +117 -0
- package/extensions/ahp/internal/settings/settings_test.go +104 -0
- package/extensions/ahp/internal/svc/etag_other.go +15 -0
- package/extensions/ahp/internal/svc/etag_unix.go +34 -0
- package/extensions/ahp/internal/svc/glob.go +197 -0
- package/extensions/ahp/internal/svc/mime.go +37 -0
- package/extensions/ahp/internal/svc/paths.go +108 -0
- package/extensions/ahp/internal/svc/pty.go +64 -0
- package/extensions/ahp/internal/svc/pty_darwin.go +42 -0
- package/extensions/ahp/internal/svc/pty_linux.go +36 -0
- package/extensions/ahp/internal/svc/pty_other.go +9 -0
- package/extensions/ahp/internal/svc/pty_test.go +114 -0
- package/extensions/ahp/internal/svc/pty_unix.go +147 -0
- package/extensions/ahp/internal/svc/resource.go +495 -0
- package/extensions/ahp/internal/svc/resource_test.go +501 -0
- package/extensions/ahp/internal/svc/stat_bsd.go +9 -0
- package/extensions/ahp/internal/svc/stat_linux.go +9 -0
- package/extensions/ahp/internal/svc/terminal.go +454 -0
- package/extensions/ahp/internal/svc/terminal_test.go +512 -0
- package/extensions/ahp/internal/svc/watch.go +590 -0
- package/extensions/ahp/internal/svc/watch_test.go +627 -0
- package/extensions/ahp/internal/svc/watchevents_test.go +452 -0
- package/extensions/ahp/internal/svc/watchpolicy.go +81 -0
- package/extensions/ahp/internal/svc/watchpolicy_test.go +151 -0
- package/extensions/ahp/internal/svc/watchracy_test.go +61 -0
- package/extensions/ahp/internal/testkit/schema/LICENSE-agent-host-protocol +21 -0
- package/extensions/ahp/internal/testkit/schema/actions.schema.json +9208 -0
- package/extensions/ahp/internal/testkit/schema/commands.schema.json +10862 -0
- package/extensions/ahp/internal/testkit/schema/errors.schema.json +10928 -0
- package/extensions/ahp/internal/testkit/schema/notifications.schema.json +6667 -0
- package/extensions/ahp/internal/testkit/schema/state.schema.json +6392 -0
- package/extensions/ahp/internal/testkit/schema.go +360 -0
- package/extensions/ahp/internal/testkit/testkit.go +367 -0
- package/extensions/ahp/internal/twin/twin.go +27 -0
- package/extensions/ahp/internal/wire/dispatchable.go +106 -0
- package/extensions/ahp/internal/wire/dispatchable_list.go +15 -0
- package/extensions/ahp/internal/wire/helpers_test.go +5 -0
- package/extensions/ahp/internal/wire/wire.go +218 -0
- package/extensions/ahp/internal/wire/wire_test.go +123 -0
- package/extensions/ahp/internal/ws/helpers_test.go +7 -0
- package/extensions/ahp/internal/ws/vscode_test.go +198 -0
- package/extensions/ahp/internal/ws/ws.go +674 -0
- package/extensions/ahp/internal/ws/ws_test.go +324 -0
- package/extensions/ahp/realpig_test.go +589 -0
- package/extensions/ahp/runtime.go +311 -0
- package/extensions/ahp/runtime_test.go +110 -0
- package/extensions/ahp/testdata/upstream-tests.json +3833 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/LICENSE +21 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/NOTICE-PIGPEN.md +18 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/client.go +1011 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/error.go +111 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/multi_host_state_mirror.go +239 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/reducers.go +1939 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahp/transport.go +176 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/actions.generated.go +2447 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/commands.generated.go +1546 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/common.go +205 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/errors.generated.go +65 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/messages.generated.go +138 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/notifications.generated.go +264 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/state.generated.go +6171 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/ahptypes/version.generated.go +31 -0
- package/extensions/ahp/third_party/agent-host-protocol-go/go.mod +3 -0
- package/extensions/ahp/twins_test.go +91 -0
- package/package.json +40 -0
- package/proof/PORT.md +121 -0
- package/proof/mutations.json +152 -0
- package/proof/oracle/LICENSE +21 -0
- package/proof/oracle/README.md +120 -0
- package/proof/oracle/UPSTREAM.md +7 -0
- package/proof/oracle/package.json +68 -0
- package/proof/oracle/src/bin/cli.ts +66 -0
- package/proof/oracle/src/bin/tunnel.ts +128 -0
- package/proof/oracle/src/channels/chat.ts +134 -0
- package/proof/oracle/src/channels/root.ts +39 -0
- package/proof/oracle/src/channels/session.ts +118 -0
- package/proof/oracle/src/channels/terminal.ts +11 -0
- package/proof/oracle/src/core/channels.ts +108 -0
- package/proof/oracle/src/core/client-workarounds.ts +358 -0
- package/proof/oracle/src/core/connection.ts +41 -0
- package/proof/oracle/src/core/host.ts +882 -0
- package/proof/oracle/src/core/sequencer.ts +75 -0
- package/proof/oracle/src/core/state-store.ts +162 -0
- package/proof/oracle/src/core/uri.ts +25 -0
- package/proof/oracle/src/host/direct-settings.ts +110 -0
- package/proof/oracle/src/host/pi-host.ts +220 -0
- package/proof/oracle/src/host/serve.ts +71 -0
- package/proof/oracle/src/host/terminal-service.ts +346 -0
- package/proof/oracle/src/pi/activity.ts +171 -0
- package/proof/oracle/src/pi/changeset-service.ts +646 -0
- package/proof/oracle/src/pi/changeset-uri.ts +64 -0
- package/proof/oracle/src/pi/chat-driver.ts +529 -0
- package/proof/oracle/src/pi/completions.ts +160 -0
- package/proof/oracle/src/pi/delete-session.ts +53 -0
- package/proof/oracle/src/pi/event-mapper.ts +648 -0
- package/proof/oracle/src/pi/git-changes.ts +605 -0
- package/proof/oracle/src/pi/history.ts +305 -0
- package/proof/oracle/src/pi/image-input.ts +56 -0
- package/proof/oracle/src/pi/image-mime.ts +8 -0
- package/proof/oracle/src/pi/in-process-backend.ts +155 -0
- package/proof/oracle/src/pi/message-input.ts +212 -0
- package/proof/oracle/src/pi/models.ts +124 -0
- package/proof/oracle/src/pi/project-trust.ts +66 -0
- package/proof/oracle/src/pi/provider.ts +2 -0
- package/proof/oracle/src/pi/resource-paths.ts +80 -0
- package/proof/oracle/src/pi/resource-service.ts +356 -0
- package/proof/oracle/src/pi/resource-watch-policy.ts +35 -0
- package/proof/oracle/src/pi/resource-watch.ts +357 -0
- package/proof/oracle/src/pi/session-catalogue.ts +318 -0
- package/proof/oracle/src/pi/session-config.ts +84 -0
- package/proof/oracle/src/pi/session-history.ts +75 -0
- package/proof/oracle/src/pi/session-hydrator.ts +219 -0
- package/proof/oracle/src/pi/session-registry.ts +815 -0
- package/proof/oracle/src/pi/session-storage.ts +29 -0
- package/proof/oracle/src/pi/session-title.ts +18 -0
- package/proof/oracle/src/pi/turn-paging.ts +94 -0
- package/proof/oracle/src/pi/user-message.ts +66 -0
- package/proof/oracle/src/protocol/errors.ts +44 -0
- package/proof/oracle/src/protocol/jsonrpc.ts +89 -0
- package/proof/oracle/src/protocol/version.ts +39 -0
- package/proof/oracle/src/transport/websocket.ts +136 -0
- package/proof/oracle/src/tunnel/devtunnel.ts +293 -0
- package/proof/oracle/src/tunnel/discovery.ts +37 -0
- package/proof/oracle/test/active-turn-reconnect.test.ts +274 -0
- package/proof/oracle/test/activity.test.ts +171 -0
- package/proof/oracle/test/changeset-lifecycle.test.serial.ts +303 -0
- package/proof/oracle/test/changeset-uri.test.ts +37 -0
- package/proof/oracle/test/changeset.test.serial.ts +487 -0
- package/proof/oracle/test/chat-driver.test.ts +691 -0
- package/proof/oracle/test/client-actions.test.ts +409 -0
- package/proof/oracle/test/client-workarounds.test.ts +320 -0
- package/proof/oracle/test/completions.test.ts +323 -0
- package/proof/oracle/test/delete-session.test.ts +142 -0
- package/proof/oracle/test/direct-settings.test.ts +81 -0
- package/proof/oracle/test/event-mapper.test.ts +619 -0
- package/proof/oracle/test/fetch-turns.test.ts +207 -0
- package/proof/oracle/test/fixtures/abort.json +711 -0
- package/proof/oracle/test/fixtures/bash-long-output.json +1312 -0
- package/proof/oracle/test/fixtures/compaction.json +6285 -0
- package/proof/oracle/test/fixtures/parallel-tools.json +2622 -0
- package/proof/oracle/test/fixtures/plain-text.json +1856 -0
- package/proof/oracle/test/fixtures/single-tool.json +1128 -0
- package/proof/oracle/test/fixtures/steering.json +3926 -0
- package/proof/oracle/test/fixtures/tool-bash.json +2372 -0
- package/proof/oracle/test/fixtures/tool-edit.json +3983 -0
- package/proof/oracle/test/fixtures/tool-error.json +2850 -0
- package/proof/oracle/test/fixtures/tool-find.json +1162 -0
- package/proof/oracle/test/fixtures/tool-grep.json +2783 -0
- package/proof/oracle/test/fixtures/tool-loop.json +1693 -0
- package/proof/oracle/test/fixtures/tool-ls.json +2427 -0
- package/proof/oracle/test/fixtures/tool-write.json +1271 -0
- package/proof/oracle/test/handshake.test.ts +275 -0
- package/proof/oracle/test/harness.ts +153 -0
- package/proof/oracle/test/hydrated-session-lifecycle.test.ts +211 -0
- package/proof/oracle/test/image-input.test.ts +28 -0
- package/proof/oracle/test/image-session.test.ts +69 -0
- package/proof/oracle/test/live-turn.test.ts +304 -0
- package/proof/oracle/test/mapper-fixtures.test.ts +293 -0
- package/proof/oracle/test/message-input.test.ts +181 -0
- package/proof/oracle/test/model-discovery.test.ts +170 -0
- package/proof/oracle/test/models.test.ts +109 -0
- package/proof/oracle/test/pi-host.test.ts +91 -0
- package/proof/oracle/test/pi-replay.test.ts +141 -0
- package/proof/oracle/test/project-trust.test.ts +125 -0
- package/proof/oracle/test/protocol-surface.test.ts +121 -0
- package/proof/oracle/test/pty.test.ts +100 -0
- package/proof/oracle/test/reconnect.test.ts +389 -0
- package/proof/oracle/test/resource-watch-policy.test.ts +78 -0
- package/proof/oracle/test/resource-watch.test.serial.ts +536 -0
- package/proof/oracle/test/resource.test.ts +499 -0
- package/proof/oracle/test/schema.test.ts +88 -0
- package/proof/oracle/test/session-catalogue.test.ts +314 -0
- package/proof/oracle/test/session-config.test.ts +224 -0
- package/proof/oracle/test/session-disposal.test.ts +364 -0
- package/proof/oracle/test/session-hydration.test.ts +194 -0
- package/proof/oracle/test/session-lifecycle.test.ts +416 -0
- package/proof/oracle/test/session-storage.test.serial.ts +32 -0
- package/proof/oracle/test/session-summary.test.ts +418 -0
- package/proof/oracle/test/subscriptions.test.ts +198 -0
- package/proof/oracle/test/support/assertions.ts +32 -0
- package/proof/oracle/test/support/async.ts +26 -0
- package/proof/oracle/test/support/hydrated-session.ts +205 -0
- package/proof/oracle/test/support/images.ts +8 -0
- package/proof/oracle/test/support/recorded-fixtures.ts +60 -0
- package/proof/oracle/test/support/recorded-scenarios.ts +145 -0
- package/proof/oracle/test/support/replay.ts +194 -0
- package/proof/oracle/test/support/schema.ts +221 -0
- package/proof/oracle/test/support/session-files.ts +12 -0
- package/proof/oracle/test/support/session-storage.ts +22 -0
- package/proof/oracle/test/support/upstream.ts +25 -0
- package/proof/oracle/test/support/watch-events.ts +108 -0
- package/proof/oracle/test/terminal-service.test.ts +495 -0
- package/proof/oracle/test/truncate.test.ts +230 -0
- package/proof/oracle/test/tunnel.test.ts +258 -0
- package/proof/oracle/test/upstream-workarounds.test.ts +37 -0
- package/proof/oracle/test/uri.test.ts +24 -0
- package/proof/oracle/test/watch-events.test.ts +118 -0
- package/proof/oracle/tsconfig.json +32 -0
- package/proof/proof-piglet/piglet.yaml +18 -0
- package/proof/tools/fakellm/go.mod +3 -0
- package/proof/tools/fakellm/main.go +109 -0
- package/proof/tools/gen-dispatchable.py +30 -0
- package/provenance.json +28 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Package ahp is the async SDK for the Agent Host Protocol (AHP).
|
|
2
|
+
//
|
|
3
|
+
// The [Client] drives a pluggable [Transport] over a JSON-RPC channel
|
|
4
|
+
// and fans incoming actions out to per-URI subscriptions and an
|
|
5
|
+
// optional top-level event stream. Reducers (see [ApplyActionToRoot],
|
|
6
|
+
// [ApplyActionToSession], [ApplyActionToTerminal],
|
|
7
|
+
// [ApplyActionToChangeset]) translate every [ahptypes.StateAction]
|
|
8
|
+
// into mutations on the matching state tree.
|
|
9
|
+
//
|
|
10
|
+
// Multi-host consumers should reach for the
|
|
11
|
+
// [github.com/microsoft/agent-host-protocol/clients/go/ahp/hosts]
|
|
12
|
+
// sub-package, which adds a registry, reconnect supervisor, and
|
|
13
|
+
// generation-checked handles on top of the single-host [Client].
|
|
14
|
+
//
|
|
15
|
+
// # Quickstart
|
|
16
|
+
//
|
|
17
|
+
// transport, err := ahpws.Connect(ctx, "ws://localhost:12345")
|
|
18
|
+
// if err != nil { /* ... */ }
|
|
19
|
+
//
|
|
20
|
+
// client, err := ahp.Connect(ctx, transport, ahp.DefaultConfig())
|
|
21
|
+
// if err != nil { /* ... */ }
|
|
22
|
+
// defer client.Shutdown(ctx)
|
|
23
|
+
//
|
|
24
|
+
// if _, err := client.Initialize(ctx, "my-client",
|
|
25
|
+
// ahptypes.SupportedProtocolVersions(), nil); err != nil { /* ... */ }
|
|
26
|
+
//
|
|
27
|
+
// _, sub, err := client.Subscribe(ctx, "ahp-session:/s1")
|
|
28
|
+
// if err != nil { /* ... */ }
|
|
29
|
+
//
|
|
30
|
+
// for evt := range sub.Events() {
|
|
31
|
+
// // handle evt ...
|
|
32
|
+
// }
|
|
33
|
+
package ahp
|
|
34
|
+
|
|
35
|
+
import (
|
|
36
|
+
"context"
|
|
37
|
+
"encoding/json"
|
|
38
|
+
"errors"
|
|
39
|
+
"fmt"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
// ─── Error types ─────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
// ErrClosed is returned by transports when the underlying connection
|
|
45
|
+
// has been cleanly closed by the remote peer.
|
|
46
|
+
var ErrClosed = errors.New("ahp: transport closed")
|
|
47
|
+
|
|
48
|
+
// ErrShutdown is returned by [Client] methods when the client (or its
|
|
49
|
+
// background driver) has been shut down.
|
|
50
|
+
var ErrShutdown = errors.New("ahp: client shut down")
|
|
51
|
+
|
|
52
|
+
// ErrSequenceGap is returned when an action envelope arrives out of
|
|
53
|
+
// sequence and the client cannot reconcile without a new snapshot. The
|
|
54
|
+
// caller should resubscribe to recover.
|
|
55
|
+
var ErrSequenceGap = errors.New("ahp: sequence gap detected; resubscribe required")
|
|
56
|
+
|
|
57
|
+
// TransportError wraps any error produced by an underlying [Transport]
|
|
58
|
+
// implementation so that callers can distinguish transport faults from
|
|
59
|
+
// protocol-level RPC errors via [errors.As].
|
|
60
|
+
type TransportError struct {
|
|
61
|
+
// Kind classifies the failure: "closed", "io", or "protocol".
|
|
62
|
+
Kind string
|
|
63
|
+
// Err is the underlying error, if any.
|
|
64
|
+
Err error
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Error implements the standard error interface.
|
|
68
|
+
func (e *TransportError) Error() string {
|
|
69
|
+
if e.Err != nil {
|
|
70
|
+
return fmt.Sprintf("ahp: transport %s: %v", e.Kind, e.Err)
|
|
71
|
+
}
|
|
72
|
+
return fmt.Sprintf("ahp: transport %s", e.Kind)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Unwrap exposes the underlying cause for [errors.Is] / [errors.As].
|
|
76
|
+
func (e *TransportError) Unwrap() error { return e.Err }
|
|
77
|
+
|
|
78
|
+
// RPCError wraps a JSON-RPC error response so the caller can branch on
|
|
79
|
+
// it via [errors.As].
|
|
80
|
+
type RPCError struct {
|
|
81
|
+
Code int32
|
|
82
|
+
Message string
|
|
83
|
+
Data json.RawMessage
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Error implements the standard error interface.
|
|
87
|
+
func (e *RPCError) Error() string {
|
|
88
|
+
return fmt.Sprintf("ahp: rpc error %d: %s", e.Code, e.Message)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// UnknownSubscriptionError is returned by [Client.Unsubscribe] when
|
|
92
|
+
// the URI is not tracked by this client.
|
|
93
|
+
type UnknownSubscriptionError struct {
|
|
94
|
+
URI string
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Error implements the standard error interface.
|
|
98
|
+
func (e *UnknownSubscriptionError) Error() string {
|
|
99
|
+
return fmt.Sprintf("ahp: no such subscription: %s", e.URI)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ─── Context helpers ────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
// ctxErr converts a context cancellation into ErrShutdown when the
|
|
105
|
+
// context expired while waiting on the client's background driver.
|
|
106
|
+
func ctxErr(ctx context.Context) error {
|
|
107
|
+
if err := ctx.Err(); err != nil {
|
|
108
|
+
return err
|
|
109
|
+
}
|
|
110
|
+
return ErrShutdown
|
|
111
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
package ahp
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"sync"
|
|
5
|
+
|
|
6
|
+
"github.com/microsoft/agent-host-protocol/clients/go/ahptypes"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// HostedResourceKey identifies a resource on a particular host.
|
|
10
|
+
// Used by [MultiHostStateMirror] as the lookup key.
|
|
11
|
+
type HostedResourceKey struct {
|
|
12
|
+
HostID string
|
|
13
|
+
URI ahptypes.URI
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// MultiHostStateMirror is a thread-safe map of (host, URI) → state
|
|
17
|
+
// snapshot. It deliberately exposes only the bare minimum needed to
|
|
18
|
+
// drive a UI that observes multiple hosts simultaneously: write
|
|
19
|
+
// snapshots in, read them back, drop them when the host or resource
|
|
20
|
+
// disappears.
|
|
21
|
+
//
|
|
22
|
+
// The mirror has no opinion about how snapshots are kept in sync with
|
|
23
|
+
// the server — that's the consumer's job, typically by feeding action
|
|
24
|
+
// envelopes from a [HostSubscriptionEvent] stream through the matching
|
|
25
|
+
// [ApplyActionToRoot] / [ApplyActionToSession] / [ApplyActionToChat] /
|
|
26
|
+
// [ApplyActionToTerminal] reducer and re-storing the result.
|
|
27
|
+
type MultiHostStateMirror struct {
|
|
28
|
+
mu sync.RWMutex
|
|
29
|
+
roots map[string]ahptypes.RootState
|
|
30
|
+
session map[HostedResourceKey]ahptypes.SessionState
|
|
31
|
+
chat map[HostedResourceKey]ahptypes.ChatState
|
|
32
|
+
term map[HostedResourceKey]ahptypes.TerminalState
|
|
33
|
+
changes map[HostedResourceKey]ahptypes.ChangesetState
|
|
34
|
+
automationCat map[string]ahptypes.AutomationState
|
|
35
|
+
automation map[HostedResourceKey]ahptypes.AutomationEntry
|
|
36
|
+
automationRun map[HostedResourceKey]ahptypes.AutomationRunState
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// NewMultiHostStateMirror returns an empty mirror.
|
|
40
|
+
func NewMultiHostStateMirror() *MultiHostStateMirror {
|
|
41
|
+
return &MultiHostStateMirror{
|
|
42
|
+
roots: make(map[string]ahptypes.RootState),
|
|
43
|
+
session: make(map[HostedResourceKey]ahptypes.SessionState),
|
|
44
|
+
chat: make(map[HostedResourceKey]ahptypes.ChatState),
|
|
45
|
+
term: make(map[HostedResourceKey]ahptypes.TerminalState),
|
|
46
|
+
changes: make(map[HostedResourceKey]ahptypes.ChangesetState),
|
|
47
|
+
automationCat: make(map[string]ahptypes.AutomationState),
|
|
48
|
+
automation: make(map[HostedResourceKey]ahptypes.AutomationEntry),
|
|
49
|
+
automationRun: make(map[HostedResourceKey]ahptypes.AutomationRunState),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// PutRoot stores host's root snapshot.
|
|
54
|
+
func (m *MultiHostStateMirror) PutRoot(hostID string, root ahptypes.RootState) {
|
|
55
|
+
m.mu.Lock()
|
|
56
|
+
defer m.mu.Unlock()
|
|
57
|
+
m.roots[hostID] = root
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Root returns the root snapshot for hostID, or (zero, false) if
|
|
61
|
+
// none is recorded.
|
|
62
|
+
func (m *MultiHostStateMirror) Root(hostID string) (ahptypes.RootState, bool) {
|
|
63
|
+
m.mu.RLock()
|
|
64
|
+
defer m.mu.RUnlock()
|
|
65
|
+
v, ok := m.roots[hostID]
|
|
66
|
+
return v, ok
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// PutSession stores a session snapshot under (hostID, uri).
|
|
70
|
+
func (m *MultiHostStateMirror) PutSession(hostID string, uri ahptypes.URI, s ahptypes.SessionState) {
|
|
71
|
+
m.mu.Lock()
|
|
72
|
+
defer m.mu.Unlock()
|
|
73
|
+
m.session[HostedResourceKey{hostID, uri}] = s
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Session returns the session snapshot at (hostID, uri), or
|
|
77
|
+
// (zero, false) if none is recorded.
|
|
78
|
+
func (m *MultiHostStateMirror) Session(hostID string, uri ahptypes.URI) (ahptypes.SessionState, bool) {
|
|
79
|
+
m.mu.RLock()
|
|
80
|
+
defer m.mu.RUnlock()
|
|
81
|
+
v, ok := m.session[HostedResourceKey{hostID, uri}]
|
|
82
|
+
return v, ok
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// PutChat stores a chat snapshot under (hostID, uri).
|
|
86
|
+
func (m *MultiHostStateMirror) PutChat(hostID string, uri ahptypes.URI, c ahptypes.ChatState) {
|
|
87
|
+
m.mu.Lock()
|
|
88
|
+
defer m.mu.Unlock()
|
|
89
|
+
m.chat[HostedResourceKey{hostID, uri}] = c
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Chat returns the chat snapshot at (hostID, uri), or
|
|
93
|
+
// (zero, false) if none is recorded.
|
|
94
|
+
func (m *MultiHostStateMirror) Chat(hostID string, uri ahptypes.URI) (ahptypes.ChatState, bool) {
|
|
95
|
+
m.mu.RLock()
|
|
96
|
+
defer m.mu.RUnlock()
|
|
97
|
+
v, ok := m.chat[HostedResourceKey{hostID, uri}]
|
|
98
|
+
return v, ok
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// PutTerminal stores a terminal snapshot under (hostID, uri).
|
|
102
|
+
func (m *MultiHostStateMirror) PutTerminal(hostID string, uri ahptypes.URI, t ahptypes.TerminalState) {
|
|
103
|
+
m.mu.Lock()
|
|
104
|
+
defer m.mu.Unlock()
|
|
105
|
+
m.term[HostedResourceKey{hostID, uri}] = t
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Terminal returns the terminal snapshot at (hostID, uri), or
|
|
109
|
+
// (zero, false) if none is recorded.
|
|
110
|
+
func (m *MultiHostStateMirror) Terminal(hostID string, uri ahptypes.URI) (ahptypes.TerminalState, bool) {
|
|
111
|
+
m.mu.RLock()
|
|
112
|
+
defer m.mu.RUnlock()
|
|
113
|
+
v, ok := m.term[HostedResourceKey{hostID, uri}]
|
|
114
|
+
return v, ok
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// PutChangeset stores a changeset snapshot under (hostID, uri).
|
|
118
|
+
func (m *MultiHostStateMirror) PutChangeset(hostID string, uri ahptypes.URI, c ahptypes.ChangesetState) {
|
|
119
|
+
m.mu.Lock()
|
|
120
|
+
defer m.mu.Unlock()
|
|
121
|
+
m.changes[HostedResourceKey{hostID, uri}] = c
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Changeset returns the changeset snapshot at (hostID, uri), or
|
|
125
|
+
// (zero, false) if none is recorded.
|
|
126
|
+
func (m *MultiHostStateMirror) Changeset(hostID string, uri ahptypes.URI) (ahptypes.ChangesetState, bool) {
|
|
127
|
+
m.mu.RLock()
|
|
128
|
+
defer m.mu.RUnlock()
|
|
129
|
+
v, ok := m.changes[HostedResourceKey{hostID, uri}]
|
|
130
|
+
return v, ok
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// PutAutomationCatalog stores a host's automation catalogue snapshot and
|
|
134
|
+
// refreshes the per-automation lookup.
|
|
135
|
+
func (m *MultiHostStateMirror) PutAutomationCatalog(hostID string, catalog ahptypes.AutomationState) {
|
|
136
|
+
m.mu.Lock()
|
|
137
|
+
defer m.mu.Unlock()
|
|
138
|
+
m.automationCat[hostID] = catalog
|
|
139
|
+
for key := range m.automation {
|
|
140
|
+
if key.HostID == hostID {
|
|
141
|
+
delete(m.automation, key)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for _, automation := range catalog.Entries {
|
|
145
|
+
m.automation[HostedResourceKey{hostID, automation.Resource}] = automation
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// AutomationCatalog returns the automation catalogue for hostID.
|
|
150
|
+
func (m *MultiHostStateMirror) AutomationCatalog(hostID string) (ahptypes.AutomationState, bool) {
|
|
151
|
+
m.mu.RLock()
|
|
152
|
+
defer m.mu.RUnlock()
|
|
153
|
+
v, ok := m.automationCat[hostID]
|
|
154
|
+
return v, ok
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Automation returns the automation snapshot at (hostID, uri).
|
|
158
|
+
func (m *MultiHostStateMirror) Automation(hostID string, uri ahptypes.URI) (ahptypes.AutomationEntry, bool) {
|
|
159
|
+
m.mu.RLock()
|
|
160
|
+
defer m.mu.RUnlock()
|
|
161
|
+
v, ok := m.automation[HostedResourceKey{hostID, uri}]
|
|
162
|
+
return v, ok
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// PutAutomationRun stores an automation-run snapshot under (hostID, uri).
|
|
166
|
+
func (m *MultiHostStateMirror) PutAutomationRun(hostID string, uri ahptypes.URI, run ahptypes.AutomationRunState) {
|
|
167
|
+
m.mu.Lock()
|
|
168
|
+
defer m.mu.Unlock()
|
|
169
|
+
m.automationRun[HostedResourceKey{hostID, uri}] = run
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// AutomationRun returns the automation-run snapshot at (hostID, uri).
|
|
173
|
+
func (m *MultiHostStateMirror) AutomationRun(hostID string, uri ahptypes.URI) (ahptypes.AutomationRunState, bool) {
|
|
174
|
+
m.mu.RLock()
|
|
175
|
+
defer m.mu.RUnlock()
|
|
176
|
+
v, ok := m.automationRun[HostedResourceKey{hostID, uri}]
|
|
177
|
+
return v, ok
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// DropHost removes every snapshot belonging to hostID. Use when a
|
|
181
|
+
// host is removed from the multi-host registry.
|
|
182
|
+
func (m *MultiHostStateMirror) DropHost(hostID string) {
|
|
183
|
+
m.mu.Lock()
|
|
184
|
+
defer m.mu.Unlock()
|
|
185
|
+
delete(m.roots, hostID)
|
|
186
|
+
delete(m.automationCat, hostID)
|
|
187
|
+
for k := range m.session {
|
|
188
|
+
if k.HostID == hostID {
|
|
189
|
+
delete(m.session, k)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
for k := range m.chat {
|
|
193
|
+
if k.HostID == hostID {
|
|
194
|
+
delete(m.chat, k)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for k := range m.term {
|
|
198
|
+
if k.HostID == hostID {
|
|
199
|
+
delete(m.term, k)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for k := range m.changes {
|
|
203
|
+
if k.HostID == hostID {
|
|
204
|
+
delete(m.changes, k)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
for k := range m.automation {
|
|
208
|
+
if k.HostID == hostID {
|
|
209
|
+
delete(m.automation, k)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for k := range m.automationRun {
|
|
213
|
+
if k.HostID == hostID {
|
|
214
|
+
delete(m.automationRun, k)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// DropResource removes the snapshot at (hostID, uri) across every
|
|
220
|
+
// resource kind. No-op if no snapshot exists.
|
|
221
|
+
func (m *MultiHostStateMirror) DropResource(hostID string, uri ahptypes.URI) {
|
|
222
|
+
m.mu.Lock()
|
|
223
|
+
defer m.mu.Unlock()
|
|
224
|
+
k := HostedResourceKey{hostID, uri}
|
|
225
|
+
if uri == "ahp-automations://" {
|
|
226
|
+
delete(m.automationCat, hostID)
|
|
227
|
+
for key := range m.automation {
|
|
228
|
+
if key.HostID == hostID {
|
|
229
|
+
delete(m.automation, key)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
delete(m.session, k)
|
|
234
|
+
delete(m.chat, k)
|
|
235
|
+
delete(m.term, k)
|
|
236
|
+
delete(m.changes, k)
|
|
237
|
+
delete(m.automation, k)
|
|
238
|
+
delete(m.automationRun, k)
|
|
239
|
+
}
|