@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,328 @@
|
|
|
1
|
+
// Package live adapts the running PiG session, seen through the public Go SDK, to the agent
|
|
2
|
+
// interfaces the AHP host drives (pi.Backend and pi.SessionStore). The upstream host embeds Pi
|
|
3
|
+
// and runs many sessions in-process; an extension lives inside ONE session, so exactly that
|
|
4
|
+
// session can be served. Anything else fails with a clear error.
|
|
5
|
+
package live
|
|
6
|
+
|
|
7
|
+
import (
|
|
8
|
+
"context"
|
|
9
|
+
"encoding/json"
|
|
10
|
+
"errors"
|
|
11
|
+
"fmt"
|
|
12
|
+
"sync"
|
|
13
|
+
|
|
14
|
+
sdk "github.com/MichaelKinsy/PiG/extensions/sdk"
|
|
15
|
+
ahptypes "github.com/microsoft/agent-host-protocol/clients/go/ahptypes"
|
|
16
|
+
|
|
17
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/mapper"
|
|
18
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/pi"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
// ErrReplaced is returned once the PiG session this adapter was attached to has been replaced
|
|
22
|
+
// (new session, resume, fork): a retained SDK context belongs to the runtime it was captured in.
|
|
23
|
+
var ErrReplaced = errors.New("the PiG session was replaced; restart the AHP listener to serve the new one")
|
|
24
|
+
|
|
25
|
+
// forwarded are the agent events the AHP event mapper consumes.
|
|
26
|
+
var forwarded = []string{
|
|
27
|
+
sdk.EventAgentStart, sdk.EventTurnStart, sdk.EventTurnEnd,
|
|
28
|
+
sdk.EventMessageStart, sdk.EventMessageUpdate, sdk.EventMessageEnd,
|
|
29
|
+
sdk.EventToolExecutionStart, sdk.EventToolExecutionUpdate, sdk.EventToolExecutionEnd,
|
|
30
|
+
sdk.EventAgentEnd, sdk.EventAgentSettled,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Session is the live PiG session as the AHP host sees it.
|
|
34
|
+
type Session struct {
|
|
35
|
+
mu sync.Mutex
|
|
36
|
+
ctx sdk.Context
|
|
37
|
+
hasCtx bool
|
|
38
|
+
id string
|
|
39
|
+
cwd string
|
|
40
|
+
listeners map[int]func(mapper.Event)
|
|
41
|
+
nextID int
|
|
42
|
+
steering []string // pending steering texts, for the synthesised queue_update
|
|
43
|
+
onModel func()
|
|
44
|
+
|
|
45
|
+
// Log receives diagnostics; nil discards them.
|
|
46
|
+
Log func(format string, args ...any)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// New creates an adapter that has not seen a session yet.
|
|
50
|
+
func New() *Session { return &Session{listeners: map[int]func(mapper.Event){}} }
|
|
51
|
+
|
|
52
|
+
func (s *Session) logf(format string, args ...any) {
|
|
53
|
+
if s.Log != nil {
|
|
54
|
+
s.Log(format, args...)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Register wires the adapter's event handlers to the extension. onStart runs on every
|
|
59
|
+
// session_start with the retained context, the session id and its working directory.
|
|
60
|
+
func (s *Session) Register(e *sdk.Extension, onStart func(ctx sdk.Context, sessionID, cwd, reason string), onShutdown func(ctx sdk.Context, reason string)) {
|
|
61
|
+
e.OnSessionStart(func(ctx sdk.Context, data map[string]any) (any, error) {
|
|
62
|
+
id, err := ctx.GetSessionID()
|
|
63
|
+
if err != nil {
|
|
64
|
+
return nil, fmt.Errorf("ahp: cannot read the session id: %w", err)
|
|
65
|
+
}
|
|
66
|
+
s.mu.Lock()
|
|
67
|
+
s.ctx, s.hasCtx, s.id, s.cwd = ctx, true, id, ctx.Cwd()
|
|
68
|
+
s.steering = nil
|
|
69
|
+
s.mu.Unlock()
|
|
70
|
+
reason, _ := data["reason"].(string)
|
|
71
|
+
if onStart != nil {
|
|
72
|
+
onStart(ctx, id, ctx.Cwd(), reason)
|
|
73
|
+
}
|
|
74
|
+
return nil, nil
|
|
75
|
+
})
|
|
76
|
+
e.OnSessionShutdown(func(ctx sdk.Context, data map[string]any) (any, error) {
|
|
77
|
+
s.mu.Lock()
|
|
78
|
+
s.hasCtx = false
|
|
79
|
+
s.mu.Unlock()
|
|
80
|
+
if onShutdown != nil {
|
|
81
|
+
reason, _ := data["reason"].(string)
|
|
82
|
+
onShutdown(ctx, reason)
|
|
83
|
+
}
|
|
84
|
+
return nil, nil
|
|
85
|
+
})
|
|
86
|
+
for _, name := range forwarded {
|
|
87
|
+
e.OnEvent(name, func(_ sdk.Context, data map[string]any) (any, error) {
|
|
88
|
+
s.deliver(name, data)
|
|
89
|
+
return nil, nil
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
e.OnEvent(sdk.EventModelSelect, func(sdk.Context, map[string]any) (any, error) {
|
|
93
|
+
s.mu.Lock()
|
|
94
|
+
fn := s.onModel
|
|
95
|
+
s.mu.Unlock()
|
|
96
|
+
if fn != nil {
|
|
97
|
+
fn()
|
|
98
|
+
}
|
|
99
|
+
return nil, nil
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// OnModelChanged registers fn to run when the active model changes.
|
|
104
|
+
func (s *Session) OnModelChanged(fn func()) { s.mu.Lock(); s.onModel = fn; s.mu.Unlock() }
|
|
105
|
+
|
|
106
|
+
// ID is the id of the live session ("" before session_start).
|
|
107
|
+
func (s *Session) ID() string { s.mu.Lock(); defer s.mu.Unlock(); return s.id }
|
|
108
|
+
|
|
109
|
+
// WorkingDirectory is the live session's working directory.
|
|
110
|
+
func (s *Session) WorkingDirectory() string { s.mu.Lock(); defer s.mu.Unlock(); return s.cwd }
|
|
111
|
+
|
|
112
|
+
// Context returns the retained SDK context, or an error when there is none or its runtime ended.
|
|
113
|
+
func (s *Session) Context() (sdk.Context, error) {
|
|
114
|
+
s.mu.Lock()
|
|
115
|
+
ctx, ok := s.ctx, s.hasCtx
|
|
116
|
+
s.mu.Unlock()
|
|
117
|
+
if !ok {
|
|
118
|
+
return sdk.Context{}, errors.New("no PiG session is running")
|
|
119
|
+
}
|
|
120
|
+
if err := ctx.Err(); err != nil {
|
|
121
|
+
return sdk.Context{}, fmt.Errorf("%w: %v", ErrReplaced, err)
|
|
122
|
+
}
|
|
123
|
+
return ctx, nil
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
func (s *Session) deliver(name string, data map[string]any) {
|
|
127
|
+
event := mapper.Event{}
|
|
128
|
+
for k, v := range data {
|
|
129
|
+
event[k] = v
|
|
130
|
+
}
|
|
131
|
+
event["type"] = name
|
|
132
|
+
// PiG reports the system prompt as a message; it is neither conversation nor input.
|
|
133
|
+
if name == sdk.EventMessageStart || name == sdk.EventMessageEnd {
|
|
134
|
+
if msg, _ := event["message"].(map[string]any); msg != nil && msg["role"] == "system" {
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
var queueUpdate mapper.Event
|
|
139
|
+
if name == sdk.EventMessageStart {
|
|
140
|
+
if msg, _ := event["message"].(map[string]any); msg != nil && msg["role"] == "user" {
|
|
141
|
+
queueUpdate = s.consumeSteering(msg)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
s.emit(event)
|
|
145
|
+
if queueUpdate != nil {
|
|
146
|
+
s.emit(queueUpdate)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
func (s *Session) emit(event mapper.Event) {
|
|
151
|
+
s.mu.Lock()
|
|
152
|
+
listeners := make([]func(mapper.Event), 0, len(s.listeners))
|
|
153
|
+
for i := 0; i < s.nextID; i++ {
|
|
154
|
+
if l, ok := s.listeners[i]; ok {
|
|
155
|
+
listeners = append(listeners, l)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
s.mu.Unlock()
|
|
159
|
+
for _, l := range listeners {
|
|
160
|
+
l(event)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// consumeSteering drops a delivered steering message from the pending list and returns the
|
|
165
|
+
// queue_update Pi would have sent (the SDK carries no such event).
|
|
166
|
+
func (s *Session) consumeSteering(message map[string]any) mapper.Event {
|
|
167
|
+
text := mapper.TextFromPiUserContent(message["content"])
|
|
168
|
+
s.mu.Lock()
|
|
169
|
+
defer s.mu.Unlock()
|
|
170
|
+
for i, pending := range s.steering {
|
|
171
|
+
if pending == text {
|
|
172
|
+
s.steering = append(append([]string(nil), s.steering[:i]...), s.steering[i+1:]...)
|
|
173
|
+
return s.queueUpdateLocked()
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return nil
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func (s *Session) queueUpdateLocked() mapper.Event {
|
|
180
|
+
steering := make([]any, len(s.steering))
|
|
181
|
+
for i, t := range s.steering {
|
|
182
|
+
steering[i] = t
|
|
183
|
+
}
|
|
184
|
+
return mapper.Event{"type": "queue_update", "steering": steering, "followUp": []any{}}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ── pi.Backend ──────────────────────────────────────────────────────────
|
|
188
|
+
|
|
189
|
+
// Subscribe implements pi.Backend.
|
|
190
|
+
func (s *Session) Subscribe(listener func(mapper.Event)) func() {
|
|
191
|
+
s.mu.Lock()
|
|
192
|
+
id := s.nextID
|
|
193
|
+
s.nextID++
|
|
194
|
+
s.listeners[id] = listener
|
|
195
|
+
s.mu.Unlock()
|
|
196
|
+
return func() { s.mu.Lock(); delete(s.listeners, id); s.mu.Unlock() }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
func content(text string, images []mapper.Image) (any, error) {
|
|
200
|
+
if len(images) == 0 {
|
|
201
|
+
return text, nil
|
|
202
|
+
}
|
|
203
|
+
prepared, err := pi.PrepareImagesForPi(images, true)
|
|
204
|
+
if err != nil {
|
|
205
|
+
return nil, err
|
|
206
|
+
}
|
|
207
|
+
blocks := []map[string]any{{"type": "text", "text": text}}
|
|
208
|
+
for _, img := range prepared {
|
|
209
|
+
blocks = append(blocks, map[string]any{"type": "image", "data": img.Data, "mimeType": img.MimeType})
|
|
210
|
+
}
|
|
211
|
+
return blocks, nil
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Prompt implements pi.Backend.
|
|
215
|
+
func (s *Session) Prompt(ctx context.Context, text string, images []mapper.Image) error {
|
|
216
|
+
return s.send(ctx, text, images, "")
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Steer implements pi.Backend: the message is delivered to the running turn.
|
|
220
|
+
func (s *Session) Steer(ctx context.Context, text string, images []mapper.Image) error {
|
|
221
|
+
s.mu.Lock()
|
|
222
|
+
s.steering = append(s.steering, text)
|
|
223
|
+
s.mu.Unlock()
|
|
224
|
+
err := s.send(ctx, text, images, "steer")
|
|
225
|
+
if err != nil {
|
|
226
|
+
s.mu.Lock()
|
|
227
|
+
for i, pending := range s.steering {
|
|
228
|
+
if pending == text {
|
|
229
|
+
s.steering = append(s.steering[:i:i], s.steering[i+1:]...)
|
|
230
|
+
break
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
s.mu.Unlock()
|
|
234
|
+
}
|
|
235
|
+
return err
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
func (s *Session) send(ctx context.Context, text string, images []mapper.Image, deliverAs string) error {
|
|
239
|
+
if err := ctx.Err(); err != nil {
|
|
240
|
+
return err
|
|
241
|
+
}
|
|
242
|
+
sdkCtx, err := s.Context()
|
|
243
|
+
if err != nil {
|
|
244
|
+
return err
|
|
245
|
+
}
|
|
246
|
+
body, err := content(text, images)
|
|
247
|
+
if err != nil {
|
|
248
|
+
return err
|
|
249
|
+
}
|
|
250
|
+
return sdkCtx.SendUserMessage(body, deliverAs)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Abort implements pi.Backend.
|
|
254
|
+
func (s *Session) Abort(context.Context) error {
|
|
255
|
+
sdkCtx, err := s.Context()
|
|
256
|
+
if err != nil {
|
|
257
|
+
return err
|
|
258
|
+
}
|
|
259
|
+
sdkCtx.Abort()
|
|
260
|
+
return nil
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// SelectModel implements pi.ModelSelector.
|
|
264
|
+
func (s *Session) SelectModel(_ context.Context, selection ahptypes.ModelSelection) error {
|
|
265
|
+
sdkCtx, err := s.Context()
|
|
266
|
+
if err != nil {
|
|
267
|
+
return err
|
|
268
|
+
}
|
|
269
|
+
if ok, err := sdkCtx.SetModel(selection.Id); err != nil {
|
|
270
|
+
return err
|
|
271
|
+
} else if !ok {
|
|
272
|
+
return fmt.Errorf("the model %s is not available", selection.Id)
|
|
273
|
+
}
|
|
274
|
+
if raw, ok := selection.Config[pi.ThinkingConfigKey]; ok {
|
|
275
|
+
var level string
|
|
276
|
+
if json.Unmarshal(raw, &level) == nil && level != "" {
|
|
277
|
+
sdkCtx.SetThinkingLevel(level)
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return nil
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// CurrentSelection implements pi.SelectionReporter.
|
|
284
|
+
func (s *Session) CurrentSelection() *ahptypes.ModelSelection {
|
|
285
|
+
sdkCtx, err := s.Context()
|
|
286
|
+
if err != nil {
|
|
287
|
+
return nil
|
|
288
|
+
}
|
|
289
|
+
info, err := sdkCtx.GetModelInfo()
|
|
290
|
+
if err != nil || info == nil {
|
|
291
|
+
return nil
|
|
292
|
+
}
|
|
293
|
+
selection := &ahptypes.ModelSelection{Id: pi.ModelSelectionID(info.Provider, info.ID)}
|
|
294
|
+
if level, err := sdkCtx.GetThinkingLevel(); err == nil && level != "" {
|
|
295
|
+
raw, _ := json.Marshal(level)
|
|
296
|
+
selection.Config = map[string]json.RawMessage{pi.ThinkingConfigKey: raw}
|
|
297
|
+
}
|
|
298
|
+
return selection
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Models lists the models the running session can use.
|
|
302
|
+
func (s *Session) Models() []pi.Model {
|
|
303
|
+
sdkCtx, err := s.Context()
|
|
304
|
+
if err != nil {
|
|
305
|
+
return nil
|
|
306
|
+
}
|
|
307
|
+
available, err := sdkCtx.ModelRegistry().GetAvailable()
|
|
308
|
+
if err != nil {
|
|
309
|
+
s.logf("cannot list models: %v", err)
|
|
310
|
+
return nil
|
|
311
|
+
}
|
|
312
|
+
var models []pi.Model
|
|
313
|
+
for _, raw := range available {
|
|
314
|
+
if m, err := pi.ModelFromMap(raw); err == nil {
|
|
315
|
+
models = append(models, m)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return models
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// BackendFactory is the pi.BackendFactory of the composition: only the live session has a
|
|
322
|
+
// backend.
|
|
323
|
+
func (s *Session) BackendFactory(session *pi.LiveSession) (pi.Backend, error) {
|
|
324
|
+
if id := s.ID(); id == "" || session.SessionID != id {
|
|
325
|
+
return nil, fmt.Errorf("this host serves the running PiG session only; session %s is not running", session.SessionID)
|
|
326
|
+
}
|
|
327
|
+
return s, nil
|
|
328
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
package live
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"reflect"
|
|
5
|
+
"testing"
|
|
6
|
+
|
|
7
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/mapper"
|
|
8
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/pi"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// Additions: the adapter's event handling, which needs no host (the SDK-facing calls are proved
|
|
12
|
+
// against a real pig in the root package's real-pig tests).
|
|
13
|
+
|
|
14
|
+
func collect(s *Session) (*[]mapper.Event, func()) {
|
|
15
|
+
var got []mapper.Event
|
|
16
|
+
unsub := s.Subscribe(func(e mapper.Event) { got = append(got, e) })
|
|
17
|
+
return &got, unsub
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
func TestDeliverAddsTheTypeAndDropsSystemMessages(t *testing.T) {
|
|
21
|
+
s := New()
|
|
22
|
+
got, _ := collect(s)
|
|
23
|
+
s.deliver("message_start", map[string]any{"message": map[string]any{"role": "system", "content": ""}})
|
|
24
|
+
s.deliver("message_end", map[string]any{"message": map[string]any{"role": "system", "content": ""}})
|
|
25
|
+
s.deliver("agent_start", map[string]any{})
|
|
26
|
+
s.deliver("message_start", map[string]any{"message": map[string]any{"role": "assistant"}})
|
|
27
|
+
types := []any{}
|
|
28
|
+
for _, e := range *got {
|
|
29
|
+
types = append(types, e["type"])
|
|
30
|
+
}
|
|
31
|
+
if !reflect.DeepEqual(types, []any{"agent_start", "message_start"}) {
|
|
32
|
+
t.Fatalf("delivered %v", types)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func TestSubscribersAreIndependent(t *testing.T) {
|
|
37
|
+
s := New()
|
|
38
|
+
a, unsubA := collect(s)
|
|
39
|
+
b, _ := collect(s)
|
|
40
|
+
s.deliver("agent_start", map[string]any{})
|
|
41
|
+
unsubA()
|
|
42
|
+
s.deliver("agent_end", map[string]any{})
|
|
43
|
+
if len(*a) != 1 || len(*b) != 2 {
|
|
44
|
+
t.Fatalf("a=%d b=%d", len(*a), len(*b))
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func TestSteeringIsReportedConsumedWhenItsUserMessageArrives(t *testing.T) {
|
|
49
|
+
s := New()
|
|
50
|
+
got, _ := collect(s)
|
|
51
|
+
s.steering = []string{"first", "second"}
|
|
52
|
+
user := func(text string) map[string]any {
|
|
53
|
+
return map[string]any{"message": map[string]any{"role": "user", "content": []any{map[string]any{"type": "text", "text": text}}}}
|
|
54
|
+
}
|
|
55
|
+
s.deliver("message_start", user("first"))
|
|
56
|
+
// the user message itself, then the synthesised queue_update carrying what is still pending
|
|
57
|
+
if len(*got) != 2 || (*got)[1]["type"] != "queue_update" || !reflect.DeepEqual((*got)[1]["steering"], []any{"second"}) {
|
|
58
|
+
t.Fatalf("events %v", *got)
|
|
59
|
+
}
|
|
60
|
+
s.deliver("message_start", user("not queued"))
|
|
61
|
+
if len(*got) != 3 {
|
|
62
|
+
t.Fatalf("an unrelated user message must not emit a queue_update: %v", *got)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
func TestOnlyTheRunningSessionHasABackend(t *testing.T) {
|
|
67
|
+
s := New()
|
|
68
|
+
if _, err := s.BackendFactory(&pi.LiveSession{SessionID: "x"}); err == nil {
|
|
69
|
+
t.Fatal("no session is running yet")
|
|
70
|
+
}
|
|
71
|
+
s.id = "live-id"
|
|
72
|
+
if b, err := s.BackendFactory(&pi.LiveSession{SessionID: "live-id"}); err != nil || b == nil {
|
|
73
|
+
t.Fatalf("the running session must get its backend: %v", err)
|
|
74
|
+
}
|
|
75
|
+
if _, err := s.BackendFactory(&pi.LiveSession{SessionID: "other"}); err == nil {
|
|
76
|
+
t.Fatal("another session must not get a backend")
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
func TestCallsWithoutASessionFailClearly(t *testing.T) {
|
|
81
|
+
s := New()
|
|
82
|
+
if _, err := s.Context(); err == nil {
|
|
83
|
+
t.Fatal("no session, no context")
|
|
84
|
+
}
|
|
85
|
+
if err := s.Abort(nil); err == nil {
|
|
86
|
+
t.Fatal("abort without a session must fail")
|
|
87
|
+
}
|
|
88
|
+
if s.CurrentSelection() != nil || s.Models() != nil {
|
|
89
|
+
t.Fatal("nothing to report without a session")
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
package live
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
|
|
6
|
+
sdk "github.com/MichaelKinsy/PiG/extensions/sdk"
|
|
7
|
+
|
|
8
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/pi"
|
|
9
|
+
"github.com/MichaelKinsy/pigpen/ahp/internal/pisession"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// Store is a pi.SessionStore over the running session: entries come from the host's session
|
|
13
|
+
// mirror, so it is current without reading the file Pi is writing, and a rename goes through the
|
|
14
|
+
// SDK rather than into the file.
|
|
15
|
+
type Store struct{ s *Session }
|
|
16
|
+
|
|
17
|
+
// NewStore returns the live session's store.
|
|
18
|
+
func (s *Session) NewStore() *Store { return &Store{s} }
|
|
19
|
+
|
|
20
|
+
var _ pi.SessionStore = (*Store)(nil)
|
|
21
|
+
|
|
22
|
+
func (st *Store) snapshot() (*pisession.Manager, sdk.Context, error) {
|
|
23
|
+
ctx, err := st.s.Context()
|
|
24
|
+
if err != nil {
|
|
25
|
+
return nil, ctx, err
|
|
26
|
+
}
|
|
27
|
+
raws, err := ctx.GetEntries()
|
|
28
|
+
if err != nil {
|
|
29
|
+
return nil, ctx, err
|
|
30
|
+
}
|
|
31
|
+
entries := make([]pisession.Entry, 0, len(raws))
|
|
32
|
+
for _, raw := range raws {
|
|
33
|
+
var e pisession.Entry
|
|
34
|
+
if json.Unmarshal(raw, &e) == nil && e.Type() != "session" {
|
|
35
|
+
entries = append(entries, e)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
file := ""
|
|
39
|
+
if f, err := ctx.GetSessionFile(); err == nil && f != nil {
|
|
40
|
+
file = *f
|
|
41
|
+
}
|
|
42
|
+
leaf := ""
|
|
43
|
+
if l, err := ctx.GetLeafID(); err == nil && l != nil {
|
|
44
|
+
leaf = *l
|
|
45
|
+
}
|
|
46
|
+
m, err := pisession.FromEntries(st.s.WorkingDirectory(), st.s.ID(), file, entries, leaf)
|
|
47
|
+
if err != nil {
|
|
48
|
+
// A leaf the mirror does not know yet: fall back to the last entry.
|
|
49
|
+
m, err = pisession.FromEntries(st.s.WorkingDirectory(), st.s.ID(), file, entries, "")
|
|
50
|
+
}
|
|
51
|
+
return m, ctx, err
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// File implements pi.SessionStore.
|
|
55
|
+
func (st *Store) File() string {
|
|
56
|
+
ctx, err := st.s.Context()
|
|
57
|
+
if err != nil {
|
|
58
|
+
return ""
|
|
59
|
+
}
|
|
60
|
+
if f, err := ctx.GetSessionFile(); err == nil && f != nil {
|
|
61
|
+
return *f
|
|
62
|
+
}
|
|
63
|
+
return ""
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// LeafEntry implements pi.SessionStore.
|
|
67
|
+
func (st *Store) LeafEntry() pisession.Entry {
|
|
68
|
+
m, _, err := st.snapshot()
|
|
69
|
+
if err != nil {
|
|
70
|
+
return nil
|
|
71
|
+
}
|
|
72
|
+
return m.LeafEntry()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// SessionName implements pi.SessionStore.
|
|
76
|
+
func (st *Store) SessionName() string {
|
|
77
|
+
ctx, err := st.s.Context()
|
|
78
|
+
if err != nil {
|
|
79
|
+
return ""
|
|
80
|
+
}
|
|
81
|
+
if name, err := ctx.GetSessionName(); err == nil && name != nil {
|
|
82
|
+
return *name
|
|
83
|
+
}
|
|
84
|
+
return ""
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// AppendSessionInfo implements pi.SessionStore. It renames through the SDK, so the entry is
|
|
88
|
+
// appended by the session's own writer.
|
|
89
|
+
func (st *Store) AppendSessionInfo(name string) (string, error) {
|
|
90
|
+
ctx, err := st.s.Context()
|
|
91
|
+
if err != nil {
|
|
92
|
+
return "", err
|
|
93
|
+
}
|
|
94
|
+
return "", ctx.SetSessionName(name)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Branch implements pi.SessionStore.
|
|
98
|
+
func (st *Store) Branch(fromID string) []pisession.Entry {
|
|
99
|
+
m, _, err := st.snapshot()
|
|
100
|
+
if err != nil {
|
|
101
|
+
return nil
|
|
102
|
+
}
|
|
103
|
+
return m.Branch(fromID)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ContextEntries implements pi.SessionStore.
|
|
107
|
+
func (st *Store) ContextEntries() []pisession.Entry {
|
|
108
|
+
m, _, err := st.snapshot()
|
|
109
|
+
if err != nil {
|
|
110
|
+
return nil
|
|
111
|
+
}
|
|
112
|
+
return m.ContextEntries()
|
|
113
|
+
}
|