diff --git a/agent/agent.go b/agent/agent.go index c8a62fd2da..c9c3cc71c8 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -554,6 +554,7 @@ func (a *agent) initSocketServer() { server, err := agentsocket.NewServer( a.logger.Named("socket"), agentsocket.WithPath(a.socketPath), + agentsocket.WithContextManager(a.contextManager), ) if err != nil { a.logger.Error(a.hardCtx, "failed to create socket server", slog.Error(err), slog.F("path", a.socketPath)) diff --git a/agent/agentcontext/api.go b/agent/agentcontext/api.go index 5746baa041..f236579cd3 100644 --- a/agent/agentcontext/api.go +++ b/agent/agentcontext/api.go @@ -38,6 +38,7 @@ type SnapshotResource struct { SizeBytes uint64 `json:"size_bytes"` Status string `json:"status"` Error string `json:"error,omitempty"` + Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` } @@ -174,9 +175,11 @@ func (a *API) handleResync(rw http.ResponseWriter, r *http.Request) { httpapi.Write(r.Context(), rw, http.StatusOK, snapshotResponse(snap)) } -// snapshotResponse converts a Snapshot to its on-wire form for +// snapshotResponse converts a Snapshot to the JSON form returned by // the resync endpoint. Payloads are omitted; the per-resource -// payload bytes ship via the drpc PushContextState path. +// payload bytes ship via the drpc PushContextState path. Keep the +// per-resource field mapping in sync with contextSnapshotToProto in +// agent/agentsocket/service.go. func snapshotResponse(s Snapshot) SnapshotResponse { out := SnapshotResponse{ Version: s.Version, @@ -195,6 +198,7 @@ func snapshotResponse(s Snapshot) SnapshotResponse { SizeBytes: r.SizeBytes, Status: r.Status.String(), Error: r.Error, + Name: r.Name, Description: r.Description, }) } diff --git a/agent/agentsocket/client.go b/agent/agentsocket/client.go index d4a3a41f4c..c038edf1fd 100644 --- a/agent/agentsocket/client.go +++ b/agent/agentsocket/client.go @@ -16,7 +16,8 @@ import ( type Option func(*options) type options struct { - path string + path string + contextManager ContextManager } // WithPath sets the socket path. If not provided or empty, the client will @@ -30,6 +31,14 @@ func WithPath(path string) Option { } } +// WithContextManager supplies the workspace-context Manager the server uses to +// serve context source CRUD. Server-only; ignored by the client. +func WithContextManager(cm ContextManager) Option { + return func(opts *options) { + opts.contextManager = cm + } +} + // Client provides a client for communicating with the workspace agentsocket API. type Client struct { client proto.DRPCAgentSocketClient @@ -157,6 +166,92 @@ func (c *Client) UpdateAppStatus(ctx context.Context, req *agentproto.UpdateAppS return c.client.UpdateAppStatus(ctx, req) } +// ContextSources lists the workspace-context sources registered on the agent. +func (c *Client) ContextSources(ctx context.Context) ([]ContextSource, error) { + resp, err := c.client.ContextSources(ctx, &proto.ContextSourcesRequest{}) + if err != nil { + return nil, err + } + sources := make([]ContextSource, 0, len(resp.Sources)) + for _, s := range resp.Sources { + sources = append(sources, ContextSource{Path: s.GetPath()}) + } + return sources, nil +} + +// GetContextSource returns a single registered source. The path is +// canonicalized by the agent before matching. +func (c *Client) GetContextSource(ctx context.Context, path string) (ContextSource, error) { + resp, err := c.client.GetContextSource(ctx, &proto.GetContextSourceRequest{Path: path}) + if err != nil { + return ContextSource{}, err + } + return ContextSource{Path: resp.GetSource().GetPath()}, nil +} + +// AddContextSource registers a new scan root on the agent. +func (c *Client) AddContextSource(ctx context.Context, path string) (ContextSource, error) { + resp, err := c.client.AddContextSource(ctx, &proto.AddContextSourceRequest{Path: path}) + if err != nil { + return ContextSource{}, err + } + return ContextSource{Path: resp.GetSource().GetPath()}, nil +} + +// RemoveContextSource removes a previously-registered scan root. +func (c *Client) RemoveContextSource(ctx context.Context, path string) error { + _, err := c.client.RemoveContextSource(ctx, &proto.RemoveContextSourceRequest{Path: path}) + return err +} + +// GetContextSnapshot returns the agent's current resolved snapshot without +// forcing a re-walk. +func (c *Client) GetContextSnapshot(ctx context.Context) (ContextSnapshot, error) { + resp, err := c.client.GetContextSnapshot(ctx, &proto.ContextSnapshotRequest{}) + if err != nil { + return ContextSnapshot{}, err + } + return contextSnapshotFromProto(resp.GetSnapshot()), nil +} + +// ResyncContext forces a re-walk and synchronous push, returning the resulting +// snapshot. Use it as a barrier before fanning out a refresh. +func (c *Client) ResyncContext(ctx context.Context) (ContextSnapshot, error) { + resp, err := c.client.ResyncContext(ctx, &proto.ResyncContextRequest{}) + if err != nil { + return ContextSnapshot{}, err + } + return contextSnapshotFromProto(resp.GetSnapshot()), nil +} + +func contextSnapshotFromProto(s *proto.ContextSnapshot) ContextSnapshot { + if s == nil { + return ContextSnapshot{} + } + out := ContextSnapshot{ + Version: s.GetVersion(), + AggregateHash: s.GetAggregateHash(), + Resources: make([]ContextResource, 0, len(s.GetResources())), + PayloadBytes: s.GetPayloadBytes(), + SnapshotError: s.GetSnapshotError(), + } + for _, r := range s.GetResources() { + out.Resources = append(out.Resources, ContextResource{ + ID: r.GetId(), + Kind: r.GetKind(), + Source: r.GetSource(), + SourcePath: r.GetSourcePath(), + ContentHash: r.GetContentHash(), + SizeBytes: r.GetSizeBytes(), + Status: r.GetStatus(), + Error: r.GetError(), + Name: r.GetName(), + Description: r.GetDescription(), + }) + } + return out +} + // SyncStatusResponse contains the status information for a unit. type SyncStatusResponse struct { UnitName unit.ID `table:"unit,default_sort" json:"unit_name"` @@ -179,3 +274,32 @@ type DependencyInfo struct { CurrentStatus unit.Status `table:"current status" json:"current_status"` IsSatisfied bool `table:"satisfied" json:"is_satisfied"` } + +// ContextSource is a registered workspace-context scan root. +type ContextSource struct { + Path string `table:"path,default_sort" json:"path"` +} + +// ContextResource is a resolved workspace-context resource. Payload bytes are +// never carried over the socket. +type ContextResource struct { + Kind string `table:"kind,default_sort" json:"kind"` + Name string `table:"name" json:"name"` + Source string `table:"source" json:"source"` + SourcePath string `table:"source path" json:"source_path"` + Status string `table:"status" json:"status"` + SizeBytes uint64 `table:"size bytes" json:"size_bytes"` + Error string `table:"error" json:"error"` + Description string `table:"-" json:"description"` + ID string `table:"-" json:"id"` + ContentHash string `table:"-" json:"content_hash"` +} + +// ContextSnapshot is the agent's resolved workspace-context state. +type ContextSnapshot struct { + Version uint64 `json:"version"` + AggregateHash string `json:"aggregate_hash"` + Resources []ContextResource `json:"resources"` + PayloadBytes uint64 `json:"payload_bytes"` + SnapshotError string `json:"snapshot_error"` +} diff --git a/agent/agentsocket/context_test.go b/agent/agentsocket/context_test.go new file mode 100644 index 0000000000..bb82a9afe2 --- /dev/null +++ b/agent/agentsocket/context_test.go @@ -0,0 +1,194 @@ +package agentsocket_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "cdr.dev/slog/v3" + "github.com/coder/coder/v2/agent/agentcontext" + "github.com/coder/coder/v2/agent/agentsocket" + "github.com/coder/coder/v2/testutil" +) + +// fakeContextManager is an in-memory agentsocket.ContextManager for tests. +type fakeContextManager struct { + sources []agentcontext.Source + snapshot agentcontext.Snapshot + resyncErr error + resynced bool +} + +func (f *fakeContextManager) Sources() []agentcontext.Source { return f.sources } + +func (f *fakeContextManager) HasSource(path string) (string, bool) { + for _, s := range f.sources { + if s.Path == path { + return s.Path, true + } + } + return "", false +} + +func (f *fakeContextManager) AddSource(s agentcontext.Source) (agentcontext.Source, error) { + for _, existing := range f.sources { + if existing.Path == s.Path { + return existing, nil + } + } + f.sources = append(f.sources, s) + return s, nil +} + +func (f *fakeContextManager) RemoveSource(path string) error { + for i, s := range f.sources { + if s.Path == path { + f.sources = append(f.sources[:i], f.sources[i+1:]...) + return nil + } + } + return agentcontext.ErrSourceNotFound +} + +func (f *fakeContextManager) Snapshot() agentcontext.Snapshot { return f.snapshot } + +func (f *fakeContextManager) Resync(_ context.Context) (agentcontext.Snapshot, error) { + if f.resyncErr != nil { + return agentcontext.Snapshot{}, f.resyncErr + } + f.resynced = true + return f.snapshot, nil +} + +func TestDRPCAgentSocketService_Context(t *testing.T) { + t.Parallel() + + t.Run("SourceCRUDAndSnapshot", func(t *testing.T) { + t.Parallel() + + const sourcePath = "/home/coder/project" + cm := &fakeContextManager{ + snapshot: agentcontext.Snapshot{ + Version: 7, + Resources: []agentcontext.Resource{{ + ID: "instruction_file:" + sourcePath + "/AGENTS.md", + Kind: agentcontext.KindInstructionFile, + Source: sourcePath + "/AGENTS.md", + SourcePath: sourcePath, + SizeBytes: 42, + Status: agentcontext.StatusOK, + Description: "be concise", + }, { + // A built-in resource (no source path) the show filter must skip. + ID: "instruction_file:/home/coder/.coder/AGENTS.md", + Kind: agentcontext.KindInstructionFile, + Source: "/home/coder/.coder/AGENTS.md", + Status: agentcontext.StatusOK, + }}, + }, + } + + socketPath := testutil.AgentSocketPath(t) + ctx := testutil.Context(t, testutil.WaitShort) + server, err := agentsocket.NewServer( + slog.Make().Leveled(slog.LevelDebug), + agentsocket.WithPath(socketPath), + agentsocket.WithContextManager(cm), + ) + require.NoError(t, err) + defer server.Close() + + client := newSocketClient(ctx, t, socketPath) + + // Add a source. + src, err := client.AddContextSource(ctx, sourcePath) + require.NoError(t, err) + require.Equal(t, sourcePath, src.Path) + + // It shows up in the list. + sources, err := client.ContextSources(ctx) + require.NoError(t, err) + require.Len(t, sources, 1) + require.Equal(t, sourcePath, sources[0].Path) + + // Get the registered source. + got, err := client.GetContextSource(ctx, sourcePath) + require.NoError(t, err) + require.Equal(t, sourcePath, got.Path) + + // Getting an unregistered source errors. + _, err = client.GetContextSource(ctx, "/nope") + require.Error(t, err) + + // Snapshot carries resources with their source path stamped. + snap, err := client.GetContextSnapshot(ctx) + require.NoError(t, err) + require.EqualValues(t, 7, snap.Version) + require.Len(t, snap.Resources, 2) + require.Equal(t, agentcontext.KindInstructionFile.String(), snap.Resources[0].Kind) + require.Equal(t, sourcePath, snap.Resources[0].SourcePath) + require.EqualValues(t, 42, snap.Resources[0].SizeBytes) + + // Remove the source; removing again reports not found. + require.NoError(t, client.RemoveContextSource(ctx, sourcePath)) + err = client.RemoveContextSource(ctx, sourcePath) + require.Error(t, err) + require.Contains(t, err.Error(), "not found") + }) + + t.Run("Resync", func(t *testing.T) { + t.Parallel() + + cm := &fakeContextManager{snapshot: agentcontext.Snapshot{Version: 3}} + socketPath := testutil.AgentSocketPath(t) + ctx := testutil.Context(t, testutil.WaitShort) + server, err := agentsocket.NewServer( + slog.Make().Leveled(slog.LevelDebug), + agentsocket.WithPath(socketPath), + agentsocket.WithContextManager(cm), + ) + require.NoError(t, err) + defer server.Close() + + client := newSocketClient(ctx, t, socketPath) + + snap, err := client.ResyncContext(ctx) + require.NoError(t, err) + require.EqualValues(t, 3, snap.Version) + require.True(t, cm.resynced) + }) + + t.Run("NoManagerErrors", func(t *testing.T) { + t.Parallel() + + socketPath := testutil.AgentSocketPath(t) + ctx := testutil.Context(t, testutil.WaitShort) + // No WithContextManager: the context RPCs must fail cleanly. + server, err := agentsocket.NewServer( + slog.Make().Leveled(slog.LevelDebug), + agentsocket.WithPath(socketPath), + ) + require.NoError(t, err) + defer server.Close() + + client := newSocketClient(ctx, t, socketPath) + + // Every context RPC independently guards a nil context manager; + // exercise all of them so dropping a guard surfaces as a test + // failure rather than an agent-killing nil dereference in a DRPC + // handler. + _, err = client.ContextSources(ctx) + require.Error(t, err) + _, err = client.GetContextSource(ctx, "/tmp/x") + require.Error(t, err) + _, err = client.AddContextSource(ctx, "/tmp/x") + require.Error(t, err) + err = client.RemoveContextSource(ctx, "/tmp/x") + require.Error(t, err) + _, err = client.GetContextSnapshot(ctx) + require.Error(t, err) + _, err = client.ResyncContext(ctx) + require.Error(t, err) + }) +} diff --git a/agent/agentsocket/proto/agentsocket.pb.go b/agent/agentsocket/proto/agentsocket.pb.go index 298664b2d9..52a70e8a8c 100644 --- a/agent/agentsocket/proto/agentsocket.pb.go +++ b/agent/agentsocket/proto/agentsocket.pb.go @@ -795,6 +795,787 @@ func (x *SyncListResponse) GetUnits() []*UnitInfo { return nil } +// ContextSource is a user-declared scan root the agent watches for +// workspace context (instruction files, skills, MCP configs) in +// addition to its built-in defaults. Identity is the canonical path. +type ContextSource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *ContextSource) Reset() { + *x = ContextSource{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContextSource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContextSource) ProtoMessage() {} + +func (x *ContextSource) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContextSource.ProtoReflect.Descriptor instead. +func (*ContextSource) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{16} +} + +func (x *ContextSource) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type ContextSourcesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ContextSourcesRequest) Reset() { + *x = ContextSourcesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContextSourcesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContextSourcesRequest) ProtoMessage() {} + +func (x *ContextSourcesRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContextSourcesRequest.ProtoReflect.Descriptor instead. +func (*ContextSourcesRequest) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{17} +} + +type ContextSourcesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Sources []*ContextSource `protobuf:"bytes,1,rep,name=sources,proto3" json:"sources,omitempty"` +} + +func (x *ContextSourcesResponse) Reset() { + *x = ContextSourcesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContextSourcesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContextSourcesResponse) ProtoMessage() {} + +func (x *ContextSourcesResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContextSourcesResponse.ProtoReflect.Descriptor instead. +func (*ContextSourcesResponse) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{18} +} + +func (x *ContextSourcesResponse) GetSources() []*ContextSource { + if x != nil { + return x.Sources + } + return nil +} + +type GetContextSourceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *GetContextSourceRequest) Reset() { + *x = GetContextSourceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetContextSourceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContextSourceRequest) ProtoMessage() {} + +func (x *GetContextSourceRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContextSourceRequest.ProtoReflect.Descriptor instead. +func (*GetContextSourceRequest) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{19} +} + +func (x *GetContextSourceRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type GetContextSourceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Source *ContextSource `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` +} + +func (x *GetContextSourceResponse) Reset() { + *x = GetContextSourceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetContextSourceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContextSourceResponse) ProtoMessage() {} + +func (x *GetContextSourceResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContextSourceResponse.ProtoReflect.Descriptor instead. +func (*GetContextSourceResponse) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{20} +} + +func (x *GetContextSourceResponse) GetSource() *ContextSource { + if x != nil { + return x.Source + } + return nil +} + +type AddContextSourceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *AddContextSourceRequest) Reset() { + *x = AddContextSourceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddContextSourceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddContextSourceRequest) ProtoMessage() {} + +func (x *AddContextSourceRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddContextSourceRequest.ProtoReflect.Descriptor instead. +func (*AddContextSourceRequest) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{21} +} + +func (x *AddContextSourceRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type AddContextSourceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Source *ContextSource `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` +} + +func (x *AddContextSourceResponse) Reset() { + *x = AddContextSourceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddContextSourceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddContextSourceResponse) ProtoMessage() {} + +func (x *AddContextSourceResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddContextSourceResponse.ProtoReflect.Descriptor instead. +func (*AddContextSourceResponse) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{22} +} + +func (x *AddContextSourceResponse) GetSource() *ContextSource { + if x != nil { + return x.Source + } + return nil +} + +type RemoveContextSourceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *RemoveContextSourceRequest) Reset() { + *x = RemoveContextSourceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveContextSourceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveContextSourceRequest) ProtoMessage() {} + +func (x *RemoveContextSourceRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveContextSourceRequest.ProtoReflect.Descriptor instead. +func (*RemoveContextSourceRequest) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{23} +} + +func (x *RemoveContextSourceRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type RemoveContextSourceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RemoveContextSourceResponse) Reset() { + *x = RemoveContextSourceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveContextSourceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveContextSourceResponse) ProtoMessage() {} + +func (x *RemoveContextSourceResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveContextSourceResponse.ProtoReflect.Descriptor instead. +func (*RemoveContextSourceResponse) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{24} +} + +// ContextResource is the on-wire form of a resolved context resource. +// Payload bytes are never sent over the socket; they ship to coderd via +// the drpc PushContextState path. Mirrors agentcontext.Resource minus +// the payload and the tool list, which reach consumers via ListMCPTools. +type ContextResource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` + Source string `protobuf:"bytes,3,opt,name=source,proto3" json:"source,omitempty"` + SourcePath string `protobuf:"bytes,4,opt,name=source_path,json=sourcePath,proto3" json:"source_path,omitempty"` + ContentHash string `protobuf:"bytes,5,opt,name=content_hash,json=contentHash,proto3" json:"content_hash,omitempty"` + SizeBytes uint64 `protobuf:"varint,6,opt,name=size_bytes,json=sizeBytes,proto3" json:"size_bytes,omitempty"` + Status string `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` + Error string `protobuf:"bytes,8,opt,name=error,proto3" json:"error,omitempty"` + Name string `protobuf:"bytes,9,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,10,opt,name=description,proto3" json:"description,omitempty"` +} + +func (x *ContextResource) Reset() { + *x = ContextResource{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContextResource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContextResource) ProtoMessage() {} + +func (x *ContextResource) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContextResource.ProtoReflect.Descriptor instead. +func (*ContextResource) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{25} +} + +func (x *ContextResource) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ContextResource) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *ContextResource) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *ContextResource) GetSourcePath() string { + if x != nil { + return x.SourcePath + } + return "" +} + +func (x *ContextResource) GetContentHash() string { + if x != nil { + return x.ContentHash + } + return "" +} + +func (x *ContextResource) GetSizeBytes() uint64 { + if x != nil { + return x.SizeBytes + } + return 0 +} + +func (x *ContextResource) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *ContextResource) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *ContextResource) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ContextResource) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// ContextSnapshot is the agent's resolved context state. +type ContextSnapshot struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + AggregateHash string `protobuf:"bytes,2,opt,name=aggregate_hash,json=aggregateHash,proto3" json:"aggregate_hash,omitempty"` + Resources []*ContextResource `protobuf:"bytes,3,rep,name=resources,proto3" json:"resources,omitempty"` + PayloadBytes uint64 `protobuf:"varint,4,opt,name=payload_bytes,json=payloadBytes,proto3" json:"payload_bytes,omitempty"` + SnapshotError string `protobuf:"bytes,5,opt,name=snapshot_error,json=snapshotError,proto3" json:"snapshot_error,omitempty"` +} + +func (x *ContextSnapshot) Reset() { + *x = ContextSnapshot{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContextSnapshot) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContextSnapshot) ProtoMessage() {} + +func (x *ContextSnapshot) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContextSnapshot.ProtoReflect.Descriptor instead. +func (*ContextSnapshot) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{26} +} + +func (x *ContextSnapshot) GetVersion() uint64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *ContextSnapshot) GetAggregateHash() string { + if x != nil { + return x.AggregateHash + } + return "" +} + +func (x *ContextSnapshot) GetResources() []*ContextResource { + if x != nil { + return x.Resources + } + return nil +} + +func (x *ContextSnapshot) GetPayloadBytes() uint64 { + if x != nil { + return x.PayloadBytes + } + return 0 +} + +func (x *ContextSnapshot) GetSnapshotError() string { + if x != nil { + return x.SnapshotError + } + return "" +} + +type ContextSnapshotRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ContextSnapshotRequest) Reset() { + *x = ContextSnapshotRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContextSnapshotRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContextSnapshotRequest) ProtoMessage() {} + +func (x *ContextSnapshotRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContextSnapshotRequest.ProtoReflect.Descriptor instead. +func (*ContextSnapshotRequest) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{27} +} + +type ContextSnapshotResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Snapshot *ContextSnapshot `protobuf:"bytes,1,opt,name=snapshot,proto3" json:"snapshot,omitempty"` +} + +func (x *ContextSnapshotResponse) Reset() { + *x = ContextSnapshotResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContextSnapshotResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContextSnapshotResponse) ProtoMessage() {} + +func (x *ContextSnapshotResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContextSnapshotResponse.ProtoReflect.Descriptor instead. +func (*ContextSnapshotResponse) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{28} +} + +func (x *ContextSnapshotResponse) GetSnapshot() *ContextSnapshot { + if x != nil { + return x.Snapshot + } + return nil +} + +type ResyncContextRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ResyncContextRequest) Reset() { + *x = ResyncContextRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResyncContextRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResyncContextRequest) ProtoMessage() {} + +func (x *ResyncContextRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResyncContextRequest.ProtoReflect.Descriptor instead. +func (*ResyncContextRequest) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{29} +} + +type ResyncContextResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Snapshot *ContextSnapshot `protobuf:"bytes,1,opt,name=snapshot,proto3" json:"snapshot,omitempty"` +} + +func (x *ResyncContextResponse) Reset() { + *x = ResyncContextResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResyncContextResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResyncContextResponse) ProtoMessage() {} + +func (x *ResyncContextResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_agentsocket_proto_agentsocket_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResyncContextResponse.ProtoReflect.Descriptor instead. +func (*ResyncContextResponse) Descriptor() ([]byte, []int) { + return file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP(), []int{30} +} + +func (x *ResyncContextResponse) GetSnapshot() *ContextSnapshot { + if x != nil { + return x.Snapshot + } + return nil +} + var File_agent_agentsocket_proto_agentsocket_proto protoreflect.FileDescriptor var file_agent_agentsocket_proto_agentsocket_proto_rawDesc = []byte{ @@ -858,59 +1639,180 @@ var file_agent_agentsocket_proto_agentsocket_proto_rawDesc = []byte{ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x69, - 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x32, 0xfa, 0x05, 0x0a, - 0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x4d, 0x0a, 0x04, - 0x50, 0x69, 0x6e, 0x67, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x09, 0x53, - 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x22, 0x23, 0x0a, 0x0d, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, + 0x68, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x16, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x22, 0x2d, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, + 0x74, 0x68, 0x22, 0x57, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, + 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x2d, 0x0a, 0x17, 0x41, + 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x57, 0x0a, 0x18, 0x41, 0x64, + 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x22, 0x30, 0x0a, 0x1a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x1d, 0x0a, 0x1b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x94, 0x02, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x69, + 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xe3, 0x01, 0x0a, 0x0f, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x48, 0x61, 0x73, 0x68, + 0x12, 0x43, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5c, 0x0a, 0x17, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x08, 0x53, 0x79, 0x6e, - 0x63, 0x57, 0x61, 0x6e, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, - 0x63, 0x57, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, + 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x73, + 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x5a, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x57, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, - 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x09, 0x53, - 0x79, 0x6e, 0x63, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x32, 0xa6, 0x0b, + 0x0a, 0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x4d, 0x0a, + 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x61, 0x64, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0a, 0x53, 0x79, 0x6e, - 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x28, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x08, 0x53, 0x79, - 0x6e, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, + 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x09, + 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x08, 0x53, 0x79, + 0x6e, 0x63, 0x57, 0x61, 0x6e, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, - 0x6e, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, + 0x6e, 0x63, 0x57, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, - 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, - 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x57, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, + 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x09, + 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x61, + 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0a, 0x53, 0x79, + 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x08, 0x53, + 0x79, 0x6e, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x0e, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2b, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2d, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x10, 0x41, 0x64, + 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2d, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, + 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x12, 0x47, 0x65, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, + 0x2c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, + 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0d, + 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x2a, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -925,7 +1827,7 @@ func file_agent_agentsocket_proto_agentsocket_proto_rawDescGZIP() []byte { return file_agent_agentsocket_proto_agentsocket_proto_rawDescData } -var file_agent_agentsocket_proto_agentsocket_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_agent_agentsocket_proto_agentsocket_proto_msgTypes = make([]protoimpl.MessageInfo, 31) var file_agent_agentsocket_proto_agentsocket_proto_goTypes = []interface{}{ (*PingRequest)(nil), // 0: coder.agentsocket.v1.PingRequest (*PingResponse)(nil), // 1: coder.agentsocket.v1.PingResponse @@ -943,33 +1845,66 @@ var file_agent_agentsocket_proto_agentsocket_proto_goTypes = []interface{}{ (*SyncListRequest)(nil), // 13: coder.agentsocket.v1.SyncListRequest (*UnitInfo)(nil), // 14: coder.agentsocket.v1.UnitInfo (*SyncListResponse)(nil), // 15: coder.agentsocket.v1.SyncListResponse - (*proto.UpdateAppStatusRequest)(nil), // 16: coder.agent.v2.UpdateAppStatusRequest - (*proto.UpdateAppStatusResponse)(nil), // 17: coder.agent.v2.UpdateAppStatusResponse + (*ContextSource)(nil), // 16: coder.agentsocket.v1.ContextSource + (*ContextSourcesRequest)(nil), // 17: coder.agentsocket.v1.ContextSourcesRequest + (*ContextSourcesResponse)(nil), // 18: coder.agentsocket.v1.ContextSourcesResponse + (*GetContextSourceRequest)(nil), // 19: coder.agentsocket.v1.GetContextSourceRequest + (*GetContextSourceResponse)(nil), // 20: coder.agentsocket.v1.GetContextSourceResponse + (*AddContextSourceRequest)(nil), // 21: coder.agentsocket.v1.AddContextSourceRequest + (*AddContextSourceResponse)(nil), // 22: coder.agentsocket.v1.AddContextSourceResponse + (*RemoveContextSourceRequest)(nil), // 23: coder.agentsocket.v1.RemoveContextSourceRequest + (*RemoveContextSourceResponse)(nil), // 24: coder.agentsocket.v1.RemoveContextSourceResponse + (*ContextResource)(nil), // 25: coder.agentsocket.v1.ContextResource + (*ContextSnapshot)(nil), // 26: coder.agentsocket.v1.ContextSnapshot + (*ContextSnapshotRequest)(nil), // 27: coder.agentsocket.v1.ContextSnapshotRequest + (*ContextSnapshotResponse)(nil), // 28: coder.agentsocket.v1.ContextSnapshotResponse + (*ResyncContextRequest)(nil), // 29: coder.agentsocket.v1.ResyncContextRequest + (*ResyncContextResponse)(nil), // 30: coder.agentsocket.v1.ResyncContextResponse + (*proto.UpdateAppStatusRequest)(nil), // 31: coder.agent.v2.UpdateAppStatusRequest + (*proto.UpdateAppStatusResponse)(nil), // 32: coder.agent.v2.UpdateAppStatusResponse } var file_agent_agentsocket_proto_agentsocket_proto_depIdxs = []int32{ 11, // 0: coder.agentsocket.v1.SyncStatusResponse.dependencies:type_name -> coder.agentsocket.v1.DependencyInfo 14, // 1: coder.agentsocket.v1.SyncListResponse.units:type_name -> coder.agentsocket.v1.UnitInfo - 0, // 2: coder.agentsocket.v1.AgentSocket.Ping:input_type -> coder.agentsocket.v1.PingRequest - 2, // 3: coder.agentsocket.v1.AgentSocket.SyncStart:input_type -> coder.agentsocket.v1.SyncStartRequest - 4, // 4: coder.agentsocket.v1.AgentSocket.SyncWant:input_type -> coder.agentsocket.v1.SyncWantRequest - 6, // 5: coder.agentsocket.v1.AgentSocket.SyncComplete:input_type -> coder.agentsocket.v1.SyncCompleteRequest - 8, // 6: coder.agentsocket.v1.AgentSocket.SyncReady:input_type -> coder.agentsocket.v1.SyncReadyRequest - 10, // 7: coder.agentsocket.v1.AgentSocket.SyncStatus:input_type -> coder.agentsocket.v1.SyncStatusRequest - 13, // 8: coder.agentsocket.v1.AgentSocket.SyncList:input_type -> coder.agentsocket.v1.SyncListRequest - 16, // 9: coder.agentsocket.v1.AgentSocket.UpdateAppStatus:input_type -> coder.agent.v2.UpdateAppStatusRequest - 1, // 10: coder.agentsocket.v1.AgentSocket.Ping:output_type -> coder.agentsocket.v1.PingResponse - 3, // 11: coder.agentsocket.v1.AgentSocket.SyncStart:output_type -> coder.agentsocket.v1.SyncStartResponse - 5, // 12: coder.agentsocket.v1.AgentSocket.SyncWant:output_type -> coder.agentsocket.v1.SyncWantResponse - 7, // 13: coder.agentsocket.v1.AgentSocket.SyncComplete:output_type -> coder.agentsocket.v1.SyncCompleteResponse - 9, // 14: coder.agentsocket.v1.AgentSocket.SyncReady:output_type -> coder.agentsocket.v1.SyncReadyResponse - 12, // 15: coder.agentsocket.v1.AgentSocket.SyncStatus:output_type -> coder.agentsocket.v1.SyncStatusResponse - 15, // 16: coder.agentsocket.v1.AgentSocket.SyncList:output_type -> coder.agentsocket.v1.SyncListResponse - 17, // 17: coder.agentsocket.v1.AgentSocket.UpdateAppStatus:output_type -> coder.agent.v2.UpdateAppStatusResponse - 10, // [10:18] is the sub-list for method output_type - 2, // [2:10] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 16, // 2: coder.agentsocket.v1.ContextSourcesResponse.sources:type_name -> coder.agentsocket.v1.ContextSource + 16, // 3: coder.agentsocket.v1.GetContextSourceResponse.source:type_name -> coder.agentsocket.v1.ContextSource + 16, // 4: coder.agentsocket.v1.AddContextSourceResponse.source:type_name -> coder.agentsocket.v1.ContextSource + 25, // 5: coder.agentsocket.v1.ContextSnapshot.resources:type_name -> coder.agentsocket.v1.ContextResource + 26, // 6: coder.agentsocket.v1.ContextSnapshotResponse.snapshot:type_name -> coder.agentsocket.v1.ContextSnapshot + 26, // 7: coder.agentsocket.v1.ResyncContextResponse.snapshot:type_name -> coder.agentsocket.v1.ContextSnapshot + 0, // 8: coder.agentsocket.v1.AgentSocket.Ping:input_type -> coder.agentsocket.v1.PingRequest + 2, // 9: coder.agentsocket.v1.AgentSocket.SyncStart:input_type -> coder.agentsocket.v1.SyncStartRequest + 4, // 10: coder.agentsocket.v1.AgentSocket.SyncWant:input_type -> coder.agentsocket.v1.SyncWantRequest + 6, // 11: coder.agentsocket.v1.AgentSocket.SyncComplete:input_type -> coder.agentsocket.v1.SyncCompleteRequest + 8, // 12: coder.agentsocket.v1.AgentSocket.SyncReady:input_type -> coder.agentsocket.v1.SyncReadyRequest + 10, // 13: coder.agentsocket.v1.AgentSocket.SyncStatus:input_type -> coder.agentsocket.v1.SyncStatusRequest + 13, // 14: coder.agentsocket.v1.AgentSocket.SyncList:input_type -> coder.agentsocket.v1.SyncListRequest + 31, // 15: coder.agentsocket.v1.AgentSocket.UpdateAppStatus:input_type -> coder.agent.v2.UpdateAppStatusRequest + 17, // 16: coder.agentsocket.v1.AgentSocket.ContextSources:input_type -> coder.agentsocket.v1.ContextSourcesRequest + 19, // 17: coder.agentsocket.v1.AgentSocket.GetContextSource:input_type -> coder.agentsocket.v1.GetContextSourceRequest + 21, // 18: coder.agentsocket.v1.AgentSocket.AddContextSource:input_type -> coder.agentsocket.v1.AddContextSourceRequest + 23, // 19: coder.agentsocket.v1.AgentSocket.RemoveContextSource:input_type -> coder.agentsocket.v1.RemoveContextSourceRequest + 27, // 20: coder.agentsocket.v1.AgentSocket.GetContextSnapshot:input_type -> coder.agentsocket.v1.ContextSnapshotRequest + 29, // 21: coder.agentsocket.v1.AgentSocket.ResyncContext:input_type -> coder.agentsocket.v1.ResyncContextRequest + 1, // 22: coder.agentsocket.v1.AgentSocket.Ping:output_type -> coder.agentsocket.v1.PingResponse + 3, // 23: coder.agentsocket.v1.AgentSocket.SyncStart:output_type -> coder.agentsocket.v1.SyncStartResponse + 5, // 24: coder.agentsocket.v1.AgentSocket.SyncWant:output_type -> coder.agentsocket.v1.SyncWantResponse + 7, // 25: coder.agentsocket.v1.AgentSocket.SyncComplete:output_type -> coder.agentsocket.v1.SyncCompleteResponse + 9, // 26: coder.agentsocket.v1.AgentSocket.SyncReady:output_type -> coder.agentsocket.v1.SyncReadyResponse + 12, // 27: coder.agentsocket.v1.AgentSocket.SyncStatus:output_type -> coder.agentsocket.v1.SyncStatusResponse + 15, // 28: coder.agentsocket.v1.AgentSocket.SyncList:output_type -> coder.agentsocket.v1.SyncListResponse + 32, // 29: coder.agentsocket.v1.AgentSocket.UpdateAppStatus:output_type -> coder.agent.v2.UpdateAppStatusResponse + 18, // 30: coder.agentsocket.v1.AgentSocket.ContextSources:output_type -> coder.agentsocket.v1.ContextSourcesResponse + 20, // 31: coder.agentsocket.v1.AgentSocket.GetContextSource:output_type -> coder.agentsocket.v1.GetContextSourceResponse + 22, // 32: coder.agentsocket.v1.AgentSocket.AddContextSource:output_type -> coder.agentsocket.v1.AddContextSourceResponse + 24, // 33: coder.agentsocket.v1.AgentSocket.RemoveContextSource:output_type -> coder.agentsocket.v1.RemoveContextSourceResponse + 28, // 34: coder.agentsocket.v1.AgentSocket.GetContextSnapshot:output_type -> coder.agentsocket.v1.ContextSnapshotResponse + 30, // 35: coder.agentsocket.v1.AgentSocket.ResyncContext:output_type -> coder.agentsocket.v1.ResyncContextResponse + 22, // [22:36] is the sub-list for method output_type + 8, // [8:22] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_agent_agentsocket_proto_agentsocket_proto_init() } @@ -1170,6 +2105,186 @@ func file_agent_agentsocket_proto_agentsocket_proto_init() { return nil } } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContextSource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContextSourcesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContextSourcesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetContextSourceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetContextSourceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddContextSourceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddContextSourceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveContextSourceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveContextSourceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContextResource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContextSnapshot); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContextSnapshotRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContextSnapshotResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResyncContextRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_agentsocket_proto_agentsocket_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResyncContextResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1177,7 +2292,7 @@ func file_agent_agentsocket_proto_agentsocket_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_agent_agentsocket_proto_agentsocket_proto_rawDesc, NumEnums: 0, - NumMessages: 16, + NumMessages: 31, NumExtensions: 0, NumServices: 1, }, diff --git a/agent/agentsocket/proto/agentsocket.proto b/agent/agentsocket/proto/agentsocket.proto index ad0bbe0f7e..60349fac81 100644 --- a/agent/agentsocket/proto/agentsocket.proto +++ b/agent/agentsocket/proto/agentsocket.proto @@ -70,6 +70,79 @@ message SyncListResponse { repeated UnitInfo units = 1; } +// ContextSource is a user-declared scan root the agent watches for +// workspace context (instruction files, skills, MCP configs) in +// addition to its built-in defaults. Identity is the canonical path. +message ContextSource { + string path = 1; +} + +message ContextSourcesRequest {} + +message ContextSourcesResponse { + repeated ContextSource sources = 1; +} + +message GetContextSourceRequest { + string path = 1; +} + +message GetContextSourceResponse { + ContextSource source = 1; +} + +message AddContextSourceRequest { + string path = 1; +} + +message AddContextSourceResponse { + ContextSource source = 1; +} + +message RemoveContextSourceRequest { + string path = 1; +} + +message RemoveContextSourceResponse {} + +// ContextResource is the on-wire form of a resolved context resource. +// Payload bytes are never sent over the socket; they ship to coderd via +// the drpc PushContextState path. Mirrors agentcontext.Resource minus +// the payload and the tool list, which reach consumers via ListMCPTools. +message ContextResource { + string id = 1; + string kind = 2; + string source = 3; + string source_path = 4; + string content_hash = 5; + uint64 size_bytes = 6; + string status = 7; + string error = 8; + string name = 9; + string description = 10; +} + +// ContextSnapshot is the agent's resolved context state. +message ContextSnapshot { + uint64 version = 1; + string aggregate_hash = 2; + repeated ContextResource resources = 3; + uint64 payload_bytes = 4; + string snapshot_error = 5; +} + +message ContextSnapshotRequest {} + +message ContextSnapshotResponse { + ContextSnapshot snapshot = 1; +} + +message ResyncContextRequest {} + +message ResyncContextResponse { + ContextSnapshot snapshot = 1; +} + // AgentSocket provides direct access to the agent over local IPC. service AgentSocket { // Ping the agent to check if it is alive. @@ -88,4 +161,16 @@ service AgentSocket { rpc SyncList(SyncListRequest) returns (SyncListResponse); // Update app status, forwarded to coderd. rpc UpdateAppStatus(coder.agent.v2.UpdateAppStatusRequest) returns (coder.agent.v2.UpdateAppStatusResponse); + // List the workspace context sources registered on the agent. + rpc ContextSources(ContextSourcesRequest) returns (ContextSourcesResponse); + // Get a single registered context source by path. + rpc GetContextSource(GetContextSourceRequest) returns (GetContextSourceResponse); + // Register a new context source (additional scan root). + rpc AddContextSource(AddContextSourceRequest) returns (AddContextSourceResponse); + // Remove a previously-registered context source. + rpc RemoveContextSource(RemoveContextSourceRequest) returns (RemoveContextSourceResponse); + // Return the agent's current resolved context snapshot without forcing a re-walk. + rpc GetContextSnapshot(ContextSnapshotRequest) returns (ContextSnapshotResponse); + // Force a re-walk and synchronous push, returning the resulting snapshot (barrier). + rpc ResyncContext(ResyncContextRequest) returns (ResyncContextResponse); } diff --git a/agent/agentsocket/proto/agentsocket_drpc.pb.go b/agent/agentsocket/proto/agentsocket_drpc.pb.go index 04836e6f87..664443072d 100644 --- a/agent/agentsocket/proto/agentsocket_drpc.pb.go +++ b/agent/agentsocket/proto/agentsocket_drpc.pb.go @@ -47,6 +47,12 @@ type DRPCAgentSocketClient interface { SyncStatus(ctx context.Context, in *SyncStatusRequest) (*SyncStatusResponse, error) SyncList(ctx context.Context, in *SyncListRequest) (*SyncListResponse, error) UpdateAppStatus(ctx context.Context, in *proto1.UpdateAppStatusRequest) (*proto1.UpdateAppStatusResponse, error) + ContextSources(ctx context.Context, in *ContextSourcesRequest) (*ContextSourcesResponse, error) + GetContextSource(ctx context.Context, in *GetContextSourceRequest) (*GetContextSourceResponse, error) + AddContextSource(ctx context.Context, in *AddContextSourceRequest) (*AddContextSourceResponse, error) + RemoveContextSource(ctx context.Context, in *RemoveContextSourceRequest) (*RemoveContextSourceResponse, error) + GetContextSnapshot(ctx context.Context, in *ContextSnapshotRequest) (*ContextSnapshotResponse, error) + ResyncContext(ctx context.Context, in *ResyncContextRequest) (*ResyncContextResponse, error) } type drpcAgentSocketClient struct { @@ -131,6 +137,60 @@ func (c *drpcAgentSocketClient) UpdateAppStatus(ctx context.Context, in *proto1. return out, nil } +func (c *drpcAgentSocketClient) ContextSources(ctx context.Context, in *ContextSourcesRequest) (*ContextSourcesResponse, error) { + out := new(ContextSourcesResponse) + err := c.cc.Invoke(ctx, "/coder.agentsocket.v1.AgentSocket/ContextSources", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentSocketClient) GetContextSource(ctx context.Context, in *GetContextSourceRequest) (*GetContextSourceResponse, error) { + out := new(GetContextSourceResponse) + err := c.cc.Invoke(ctx, "/coder.agentsocket.v1.AgentSocket/GetContextSource", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentSocketClient) AddContextSource(ctx context.Context, in *AddContextSourceRequest) (*AddContextSourceResponse, error) { + out := new(AddContextSourceResponse) + err := c.cc.Invoke(ctx, "/coder.agentsocket.v1.AgentSocket/AddContextSource", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentSocketClient) RemoveContextSource(ctx context.Context, in *RemoveContextSourceRequest) (*RemoveContextSourceResponse, error) { + out := new(RemoveContextSourceResponse) + err := c.cc.Invoke(ctx, "/coder.agentsocket.v1.AgentSocket/RemoveContextSource", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentSocketClient) GetContextSnapshot(ctx context.Context, in *ContextSnapshotRequest) (*ContextSnapshotResponse, error) { + out := new(ContextSnapshotResponse) + err := c.cc.Invoke(ctx, "/coder.agentsocket.v1.AgentSocket/GetContextSnapshot", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentSocketClient) ResyncContext(ctx context.Context, in *ResyncContextRequest) (*ResyncContextResponse, error) { + out := new(ResyncContextResponse) + err := c.cc.Invoke(ctx, "/coder.agentsocket.v1.AgentSocket/ResyncContext", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + type DRPCAgentSocketServer interface { Ping(context.Context, *PingRequest) (*PingResponse, error) SyncStart(context.Context, *SyncStartRequest) (*SyncStartResponse, error) @@ -140,6 +200,12 @@ type DRPCAgentSocketServer interface { SyncStatus(context.Context, *SyncStatusRequest) (*SyncStatusResponse, error) SyncList(context.Context, *SyncListRequest) (*SyncListResponse, error) UpdateAppStatus(context.Context, *proto1.UpdateAppStatusRequest) (*proto1.UpdateAppStatusResponse, error) + ContextSources(context.Context, *ContextSourcesRequest) (*ContextSourcesResponse, error) + GetContextSource(context.Context, *GetContextSourceRequest) (*GetContextSourceResponse, error) + AddContextSource(context.Context, *AddContextSourceRequest) (*AddContextSourceResponse, error) + RemoveContextSource(context.Context, *RemoveContextSourceRequest) (*RemoveContextSourceResponse, error) + GetContextSnapshot(context.Context, *ContextSnapshotRequest) (*ContextSnapshotResponse, error) + ResyncContext(context.Context, *ResyncContextRequest) (*ResyncContextResponse, error) } type DRPCAgentSocketUnimplementedServer struct{} @@ -176,9 +242,33 @@ func (s *DRPCAgentSocketUnimplementedServer) UpdateAppStatus(context.Context, *p return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } +func (s *DRPCAgentSocketUnimplementedServer) ContextSources(context.Context, *ContextSourcesRequest) (*ContextSourcesResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentSocketUnimplementedServer) GetContextSource(context.Context, *GetContextSourceRequest) (*GetContextSourceResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentSocketUnimplementedServer) AddContextSource(context.Context, *AddContextSourceRequest) (*AddContextSourceResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentSocketUnimplementedServer) RemoveContextSource(context.Context, *RemoveContextSourceRequest) (*RemoveContextSourceResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentSocketUnimplementedServer) GetContextSnapshot(context.Context, *ContextSnapshotRequest) (*ContextSnapshotResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentSocketUnimplementedServer) ResyncContext(context.Context, *ResyncContextRequest) (*ResyncContextResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + type DRPCAgentSocketDescription struct{} -func (DRPCAgentSocketDescription) NumMethods() int { return 8 } +func (DRPCAgentSocketDescription) NumMethods() int { return 14 } func (DRPCAgentSocketDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { @@ -254,6 +344,60 @@ func (DRPCAgentSocketDescription) Method(n int) (string, drpc.Encoding, drpc.Rec in1.(*proto1.UpdateAppStatusRequest), ) }, DRPCAgentSocketServer.UpdateAppStatus, true + case 8: + return "/coder.agentsocket.v1.AgentSocket/ContextSources", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentSocketServer). + ContextSources( + ctx, + in1.(*ContextSourcesRequest), + ) + }, DRPCAgentSocketServer.ContextSources, true + case 9: + return "/coder.agentsocket.v1.AgentSocket/GetContextSource", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentSocketServer). + GetContextSource( + ctx, + in1.(*GetContextSourceRequest), + ) + }, DRPCAgentSocketServer.GetContextSource, true + case 10: + return "/coder.agentsocket.v1.AgentSocket/AddContextSource", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentSocketServer). + AddContextSource( + ctx, + in1.(*AddContextSourceRequest), + ) + }, DRPCAgentSocketServer.AddContextSource, true + case 11: + return "/coder.agentsocket.v1.AgentSocket/RemoveContextSource", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentSocketServer). + RemoveContextSource( + ctx, + in1.(*RemoveContextSourceRequest), + ) + }, DRPCAgentSocketServer.RemoveContextSource, true + case 12: + return "/coder.agentsocket.v1.AgentSocket/GetContextSnapshot", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentSocketServer). + GetContextSnapshot( + ctx, + in1.(*ContextSnapshotRequest), + ) + }, DRPCAgentSocketServer.GetContextSnapshot, true + case 13: + return "/coder.agentsocket.v1.AgentSocket/ResyncContext", drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentSocketServer). + ResyncContext( + ctx, + in1.(*ResyncContextRequest), + ) + }, DRPCAgentSocketServer.ResyncContext, true default: return "", nil, nil, nil, false } @@ -390,3 +534,99 @@ func (x *drpcAgentSocket_UpdateAppStatusStream) SendAndClose(m *proto1.UpdateApp } return x.CloseSend() } + +type DRPCAgentSocket_ContextSourcesStream interface { + drpc.Stream + SendAndClose(*ContextSourcesResponse) error +} + +type drpcAgentSocket_ContextSourcesStream struct { + drpc.Stream +} + +func (x *drpcAgentSocket_ContextSourcesStream) SendAndClose(m *ContextSourcesResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgentSocket_GetContextSourceStream interface { + drpc.Stream + SendAndClose(*GetContextSourceResponse) error +} + +type drpcAgentSocket_GetContextSourceStream struct { + drpc.Stream +} + +func (x *drpcAgentSocket_GetContextSourceStream) SendAndClose(m *GetContextSourceResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgentSocket_AddContextSourceStream interface { + drpc.Stream + SendAndClose(*AddContextSourceResponse) error +} + +type drpcAgentSocket_AddContextSourceStream struct { + drpc.Stream +} + +func (x *drpcAgentSocket_AddContextSourceStream) SendAndClose(m *AddContextSourceResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgentSocket_RemoveContextSourceStream interface { + drpc.Stream + SendAndClose(*RemoveContextSourceResponse) error +} + +type drpcAgentSocket_RemoveContextSourceStream struct { + drpc.Stream +} + +func (x *drpcAgentSocket_RemoveContextSourceStream) SendAndClose(m *RemoveContextSourceResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgentSocket_GetContextSnapshotStream interface { + drpc.Stream + SendAndClose(*ContextSnapshotResponse) error +} + +type drpcAgentSocket_GetContextSnapshotStream struct { + drpc.Stream +} + +func (x *drpcAgentSocket_GetContextSnapshotStream) SendAndClose(m *ContextSnapshotResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgentSocket_ResyncContextStream interface { + drpc.Stream + SendAndClose(*ResyncContextResponse) error +} + +type drpcAgentSocket_ResyncContextStream struct { + drpc.Stream +} + +func (x *drpcAgentSocket_ResyncContextStream) SendAndClose(m *ResyncContextResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_agentsocket_proto_agentsocket_proto{}); err != nil { + return err + } + return x.CloseSend() +} diff --git a/agent/agentsocket/server.go b/agent/agentsocket/server.go index 380b792da1..605feeec05 100644 --- a/agent/agentsocket/server.go +++ b/agent/agentsocket/server.go @@ -44,8 +44,9 @@ func NewServer(logger slog.Logger, opts ...Option) (*Server, error) { logger: logger, path: options.path, service: &DRPCAgentSocketService{ - logger: logger, - unitManager: unit.NewManager(), + logger: logger, + unitManager: unit.NewManager(), + contextManager: options.contextManager, }, } diff --git a/agent/agentsocket/service.go b/agent/agentsocket/service.go index 97be1b45c5..8f2f574851 100644 --- a/agent/agentsocket/service.go +++ b/agent/agentsocket/service.go @@ -2,12 +2,14 @@ package agentsocket import ( "context" + "encoding/hex" "errors" "sync" "golang.org/x/xerrors" "cdr.dev/slog/v3" + "github.com/coder/coder/v2/agent/agentcontext" "github.com/coder/coder/v2/agent/agentsocket/proto" agentproto "github.com/coder/coder/v2/agent/proto" "github.com/coder/coder/v2/agent/unit" @@ -16,14 +18,29 @@ import ( var _ proto.DRPCAgentSocketServer = (*DRPCAgentSocketService)(nil) var ( - ErrUnitManagerNotAvailable = xerrors.New("unit manager not available") - ErrAgentAPINotConnected = xerrors.New("agent not connected to coderd") + ErrUnitManagerNotAvailable = xerrors.New("unit manager not available") + ErrAgentAPINotConnected = xerrors.New("agent not connected to coderd") + ErrContextManagerNotAvailable = xerrors.New("context manager not available") + ErrContextSourceNotFound = xerrors.New("context source not found") ) +// ContextManager is the subset of *agentcontext.Manager the socket +// service needs to serve workspace-context source CRUD. It is an +// interface so tests can supply a fake. +type ContextManager interface { + Sources() []agentcontext.Source + HasSource(path string) (canonical string, ok bool) + AddSource(s agentcontext.Source) (agentcontext.Source, error) + RemoveSource(path string) error + Snapshot() agentcontext.Snapshot + Resync(ctx context.Context) (agentcontext.Snapshot, error) +} + // DRPCAgentSocketService implements the DRPC agent socket service. type DRPCAgentSocketService struct { - unitManager *unit.Manager - logger slog.Logger + unitManager *unit.Manager + contextManager ContextManager + logger slog.Logger mu sync.Mutex agentAPI agentproto.DRPCAgentClient28 @@ -210,3 +227,107 @@ func (s *DRPCAgentSocketService) UpdateAppStatus(ctx context.Context, req *agent } return api.UpdateAppStatus(ctx, req) } + +// ContextSources lists the workspace-context sources registered on the agent. +func (s *DRPCAgentSocketService) ContextSources(_ context.Context, _ *proto.ContextSourcesRequest) (*proto.ContextSourcesResponse, error) { + if s.contextManager == nil { + return nil, ErrContextManagerNotAvailable + } + sources := s.contextManager.Sources() + out := &proto.ContextSourcesResponse{Sources: make([]*proto.ContextSource, 0, len(sources))} + for _, src := range sources { + out.Sources = append(out.Sources, &proto.ContextSource{Path: src.Path}) + } + return out, nil +} + +// GetContextSource returns a single registered source, canonicalizing the +// requested path before matching. +func (s *DRPCAgentSocketService) GetContextSource(_ context.Context, req *proto.GetContextSourceRequest) (*proto.GetContextSourceResponse, error) { + if s.contextManager == nil { + return nil, ErrContextManagerNotAvailable + } + canonical, ok := s.contextManager.HasSource(req.Path) + if !ok { + return nil, xerrors.Errorf("%q: %w", req.Path, ErrContextSourceNotFound) + } + return &proto.GetContextSourceResponse{Source: &proto.ContextSource{Path: canonical}}, nil +} + +// AddContextSource registers a new scan root and triggers a re-resolve. +func (s *DRPCAgentSocketService) AddContextSource(_ context.Context, req *proto.AddContextSourceRequest) (*proto.AddContextSourceResponse, error) { + if s.contextManager == nil { + return nil, ErrContextManagerNotAvailable + } + src, err := s.contextManager.AddSource(agentcontext.Source{Path: req.Path}) + if err != nil { + return nil, xerrors.Errorf("add context source: %w", err) + } + return &proto.AddContextSourceResponse{Source: &proto.ContextSource{Path: src.Path}}, nil +} + +// RemoveContextSource removes a previously-registered scan root. +func (s *DRPCAgentSocketService) RemoveContextSource(_ context.Context, req *proto.RemoveContextSourceRequest) (*proto.RemoveContextSourceResponse, error) { + if s.contextManager == nil { + return nil, ErrContextManagerNotAvailable + } + if err := s.contextManager.RemoveSource(req.Path); err != nil { + if errors.Is(err, agentcontext.ErrSourceNotFound) { + return nil, xerrors.Errorf("%q: %w", req.Path, ErrContextSourceNotFound) + } + return nil, xerrors.Errorf("remove context source: %w", err) + } + return &proto.RemoveContextSourceResponse{}, nil +} + +// GetContextSnapshot returns the agent's current resolved snapshot without +// forcing a re-walk. +func (s *DRPCAgentSocketService) GetContextSnapshot(_ context.Context, _ *proto.ContextSnapshotRequest) (*proto.ContextSnapshotResponse, error) { + if s.contextManager == nil { + return nil, ErrContextManagerNotAvailable + } + return &proto.ContextSnapshotResponse{Snapshot: contextSnapshotToProto(s.contextManager.Snapshot())}, nil +} + +// ResyncContext forces a re-walk and synchronous push, returning the +// resulting snapshot. Callers use it as a barrier before fanning out a +// refresh. +func (s *DRPCAgentSocketService) ResyncContext(ctx context.Context, _ *proto.ResyncContextRequest) (*proto.ResyncContextResponse, error) { + if s.contextManager == nil { + return nil, ErrContextManagerNotAvailable + } + snap, err := s.contextManager.Resync(ctx) + if err != nil { + return nil, xerrors.Errorf("resync context: %w", err) + } + return &proto.ResyncContextResponse{Snapshot: contextSnapshotToProto(snap)}, nil +} + +// contextSnapshotToProto converts an agentcontext.Snapshot to its on-wire +// form. Payload bytes are intentionally omitted; they reach coderd via the +// drpc PushContextState path. Keep the per-resource field mapping in sync +// with snapshotResponse in agent/agentcontext/api.go. +func contextSnapshotToProto(s agentcontext.Snapshot) *proto.ContextSnapshot { + out := &proto.ContextSnapshot{ + Version: s.Version, + AggregateHash: hex.EncodeToString(s.AggregateHash[:]), + Resources: make([]*proto.ContextResource, 0, len(s.Resources)), + PayloadBytes: s.PayloadBytes, + SnapshotError: s.SnapshotError, + } + for _, r := range s.Resources { + out.Resources = append(out.Resources, &proto.ContextResource{ + Id: r.ID, + Kind: r.Kind.String(), + Source: r.Source, + SourcePath: r.SourcePath, + ContentHash: hex.EncodeToString(r.ContentHash[:]), + SizeBytes: r.SizeBytes, + Status: r.Status.String(), + Error: r.Error, + Name: r.Name, + Description: r.Description, + }) + } + return out +}