diff --git a/docs/evidence/saas-dispatcher-implementation.md b/docs/evidence/saas-dispatcher-implementation.md index 4f30559..449a891 100644 --- a/docs/evidence/saas-dispatcher-implementation.md +++ b/docs/evidence/saas-dispatcher-implementation.md @@ -57,7 +57,8 @@ - 对话控制隔离验证:共享 `callflow` 不再根据转写或回复内的硬编码词推断拒联,仅处理明确的关键词/拒联事实;ASR-only 不播报开场或 TTS 回复。配置的首语音/静默期限、整通话期限与最大轮数交给媒体控制器;回复按 Unicode 字符数分片,火山 TTS 的缓存音频块数超限明确失败而不重试;不支持的插话配置在准入前拒绝。该控制器尚未接入新主 CLI,不能宣称真实通话媒体已验证。 - Agent 隔离媒体入口 `rpc.RunApprovedCall` 仅接收签发的执行快照、媒体会话、挂断动作和显式每通话 AI pipeline;缺失或 typed nil 适配器在读媒体前拒绝,无隐式 SDK/Mock 回退。测试分别由已绑定快照构建 SDK pipeline 与注入受控合成脚本的 `ApprovedMockPipeline`。签发通话期限与 AI 总期限均约束整通电话;ASR-only 不合成开场,full-AI 开场完成才采集语音。父级期限不会被“未检测到语音”掩盖,空媒体 Mock 等到上下文真正结束。当前媒体只处理 16 kHz PCM16,SDK 虽接受、但媒体不能正确处理的 24 kHz ASR/TTS 配置在 Dispatcher 与 Agent 绑定时明确拒绝,不静默播放或识别错速音频。该入口尚未连接主 CLI,也未用于真实拨号。 - 隔离 Mock AI 适配器仅消费显式冻结的模拟媒体与最终识别脚本,不手写或替代供应商协议;缺失/多余轮次、未批准的开场或助理音频明确拒绝。ASR-only 不执行开场与回复;full-AI 开场只允许一次,用户最终识别的已配置字面关键词先挂断、绝不播放该轮候选回复,未配置关键词不推断拒联。任务未配置最大轮数时严格使用共享通话流程的一轮边界,负数仍拒绝。Mock 输出不代表真实 ASR/LLM/TTS 已通过。 -- 新增 Agent 任务级在途通话栅栏 `TaskCalls`:按 D/数字租户/任务隔离;暂停或停止先拒新通话,hangup 请求取消、drain 不挂断,两者均等待已登记通话结束才确认;等待超时仍保留关闭栅栏,停止后不能恢复,同一控制重复执行不另设去重。隔离测试验证两任务互不干扰、重复结束不破坏状态。该栅栏尚未接入已认证的 Agent RPC 和主入口;Dispatcher 的持久控制仍为权威,不能据此称真实通话已受控。 +- 新增 Agent 任务级在途通话栅栏 `TaskCalls`:按 D/数字租户/任务隔离;暂停或停止先拒新通话,hangup 请求取消、drain 不挂断,两者均等待已登记通话结束才确认;等待超时仍保留关闭栅栏,停止后不能恢复,同一控制重复执行不另设去重。隔离测试验证两任务互不干扰、重复结束不破坏状态。该栅栏已由活跃会话校验的 Agent RPC 隔离单测调用,但尚未接入实际批准通话的登记/取消和主入口;Dispatcher 的持久控制仍为权威,不能据此称真实通话已受控。 +- 新增内部任务级 `ApplyApprovedTaskControl` Proto、生成物及 Dispatcher `ApprovedOriginator.SendControl`:D 每次发送前从已激活会话领取元数据,只生成独立 RPC 追踪 ID,不从 SaaS 控制虚构 command_id、幂等键或 revision;Agent 校验活跃 D 会话、数字租户、任务和 pause/stop 的 hangup/drain 政策,在 Mock 中等待已登记活动通话结束后才确认,超时保留本地停止栅栏。隔离测试覆盖拒绝伪 D/旧会话、非法字段与政策、无适配器、未知 RPC 结果不自动重试及重复控制的显式重送;**尚无实际批准通话登记或新主 CLI 接线,也未经过该控制 RPC 的双向 TLS 传输测试**。 - 验证:`PATH=/tmp/sip-go-agent-tools/bin:$PATH bash scripts/check-current-contracts.sh`、`PATH=/tmp/sip-go-agent-tools/bin:$PATH bash scripts/check-proto.sh`、`go test ./... -count=1`、`go test -race ./internal/ai ./internal/callflow ./internal/configread ./internal/dispatcher ./internal/rpc -count=1`、`go vet ./...`、`go build ./...`、`git diff --check` 均通过。 - **后续边界:** 录音直传/OSS 失败恢复及最终结果属 P06;新主 CLI 接线、真实媒体完整联动及旧路径清理属 P07;隔离端到端和 A01–A12 属 P08。真实 Agent/Asterisk、SaaS、MQ、AI 供应商联调未开展,不能由 Mock 结果代签。 diff --git a/gen/agent/agent.pb.go b/gen/agent/agent.pb.go index 8b64500..15018c7 100644 --- a/gen/agent/agent.pb.go +++ b/gen/agent/agent.pb.go @@ -3521,6 +3521,136 @@ func (x *ApplyTaskControlResponse) GetState() ExecutionState { return ExecutionState_EXECUTION_STATE_UNSPECIFIED } +// Current task-level control has no external command ID, revision CAS or +// execution binding. The authenticated session must match dispatcher_id. +type ApplyApprovedTaskControlRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + DispatcherId string `protobuf:"bytes,2,opt,name=dispatcher_id,json=dispatcherId,proto3" json:"dispatcher_id,omitempty"` + TenantId int64 `protobuf:"varint,3,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"` + TaskId string `protobuf:"bytes,4,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` + Action ControlAction `protobuf:"varint,5,opt,name=action,proto3,enum=agent.ControlAction" json:"action,omitempty"` + ActiveCallPolicy ActiveCallPolicy `protobuf:"varint,6,opt,name=active_call_policy,json=activeCallPolicy,proto3,enum=agent.ActiveCallPolicy" json:"active_call_policy,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ApplyApprovedTaskControlRequest) Reset() { + *x = ApplyApprovedTaskControlRequest{} + mi := &file_agent_agent_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ApplyApprovedTaskControlRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyApprovedTaskControlRequest) ProtoMessage() {} + +func (x *ApplyApprovedTaskControlRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_agent_proto_msgTypes[36] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyApprovedTaskControlRequest.ProtoReflect.Descriptor instead. +func (*ApplyApprovedTaskControlRequest) Descriptor() ([]byte, []int) { + return file_agent_agent_proto_rawDescGZIP(), []int{36} +} + +func (x *ApplyApprovedTaskControlRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *ApplyApprovedTaskControlRequest) GetDispatcherId() string { + if x != nil { + return x.DispatcherId + } + return "" +} + +func (x *ApplyApprovedTaskControlRequest) GetTenantId() int64 { + if x != nil { + return x.TenantId + } + return 0 +} + +func (x *ApplyApprovedTaskControlRequest) GetTaskId() string { + if x != nil { + return x.TaskId + } + return "" +} + +func (x *ApplyApprovedTaskControlRequest) GetAction() ControlAction { + if x != nil { + return x.Action + } + return ControlAction_CONTROL_ACTION_UNSPECIFIED +} + +func (x *ApplyApprovedTaskControlRequest) GetActiveCallPolicy() ActiveCallPolicy { + if x != nil { + return x.ActiveCallPolicy + } + return ActiveCallPolicy_ACTIVE_CALL_POLICY_UNSPECIFIED +} + +type ApplyApprovedTaskControlResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ApplyApprovedTaskControlResponse) Reset() { + *x = ApplyApprovedTaskControlResponse{} + mi := &file_agent_agent_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ApplyApprovedTaskControlResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyApprovedTaskControlResponse) ProtoMessage() {} + +func (x *ApplyApprovedTaskControlResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_agent_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyApprovedTaskControlResponse.ProtoReflect.Descriptor instead. +func (*ApplyApprovedTaskControlResponse) Descriptor() ([]byte, []int) { + return file_agent_agent_proto_rawDescGZIP(), []int{37} +} + +func (x *ApplyApprovedTaskControlResponse) GetAccepted() bool { + if x != nil { + return x.Accepted + } + return false +} + type QueryExecutionRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` @@ -3531,7 +3661,7 @@ type QueryExecutionRequest struct { func (x *QueryExecutionRequest) Reset() { *x = QueryExecutionRequest{} - mi := &file_agent_agent_proto_msgTypes[36] + mi := &file_agent_agent_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3543,7 +3673,7 @@ func (x *QueryExecutionRequest) String() string { func (*QueryExecutionRequest) ProtoMessage() {} func (x *QueryExecutionRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[36] + mi := &file_agent_agent_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3556,7 +3686,7 @@ func (x *QueryExecutionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryExecutionRequest.ProtoReflect.Descriptor instead. func (*QueryExecutionRequest) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{36} + return file_agent_agent_proto_rawDescGZIP(), []int{38} } func (x *QueryExecutionRequest) GetMeta() *RequestMeta { @@ -3589,7 +3719,7 @@ type ExecutionSnapshot struct { func (x *ExecutionSnapshot) Reset() { *x = ExecutionSnapshot{} - mi := &file_agent_agent_proto_msgTypes[37] + mi := &file_agent_agent_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3601,7 +3731,7 @@ func (x *ExecutionSnapshot) String() string { func (*ExecutionSnapshot) ProtoMessage() {} func (x *ExecutionSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[37] + mi := &file_agent_agent_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3614,7 +3744,7 @@ func (x *ExecutionSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionSnapshot.ProtoReflect.Descriptor instead. func (*ExecutionSnapshot) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{37} + return file_agent_agent_proto_rawDescGZIP(), []int{39} } func (x *ExecutionSnapshot) GetBinding() *ExecutionBinding { @@ -3684,7 +3814,7 @@ type QueryExecutionResponse struct { func (x *QueryExecutionResponse) Reset() { *x = QueryExecutionResponse{} - mi := &file_agent_agent_proto_msgTypes[38] + mi := &file_agent_agent_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3696,7 +3826,7 @@ func (x *QueryExecutionResponse) String() string { func (*QueryExecutionResponse) ProtoMessage() {} func (x *QueryExecutionResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[38] + mi := &file_agent_agent_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3709,7 +3839,7 @@ func (x *QueryExecutionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryExecutionResponse.ProtoReflect.Descriptor instead. func (*QueryExecutionResponse) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{38} + return file_agent_agent_proto_rawDescGZIP(), []int{40} } func (x *QueryExecutionResponse) GetMeta() *ResponseMeta { @@ -3749,7 +3879,7 @@ type ExecutionFact struct { func (x *ExecutionFact) Reset() { *x = ExecutionFact{} - mi := &file_agent_agent_proto_msgTypes[39] + mi := &file_agent_agent_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3761,7 +3891,7 @@ func (x *ExecutionFact) String() string { func (*ExecutionFact) ProtoMessage() {} func (x *ExecutionFact) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[39] + mi := &file_agent_agent_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3774,7 +3904,7 @@ func (x *ExecutionFact) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionFact.ProtoReflect.Descriptor instead. func (*ExecutionFact) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{39} + return file_agent_agent_proto_rawDescGZIP(), []int{41} } func (x *ExecutionFact) GetFactId() string { @@ -3843,7 +3973,7 @@ type ReportExecutionEventRequest struct { func (x *ReportExecutionEventRequest) Reset() { *x = ReportExecutionEventRequest{} - mi := &file_agent_agent_proto_msgTypes[40] + mi := &file_agent_agent_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3855,7 +3985,7 @@ func (x *ReportExecutionEventRequest) String() string { func (*ReportExecutionEventRequest) ProtoMessage() {} func (x *ReportExecutionEventRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[40] + mi := &file_agent_agent_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3868,7 +3998,7 @@ func (x *ReportExecutionEventRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportExecutionEventRequest.ProtoReflect.Descriptor instead. func (*ReportExecutionEventRequest) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{40} + return file_agent_agent_proto_rawDescGZIP(), []int{42} } func (x *ReportExecutionEventRequest) GetMeta() *RequestMeta { @@ -3894,7 +4024,7 @@ type ReportExecutionEventResponse struct { func (x *ReportExecutionEventResponse) Reset() { *x = ReportExecutionEventResponse{} - mi := &file_agent_agent_proto_msgTypes[41] + mi := &file_agent_agent_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3906,7 +4036,7 @@ func (x *ReportExecutionEventResponse) String() string { func (*ReportExecutionEventResponse) ProtoMessage() {} func (x *ReportExecutionEventResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[41] + mi := &file_agent_agent_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3919,7 +4049,7 @@ func (x *ReportExecutionEventResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportExecutionEventResponse.ProtoReflect.Descriptor instead. func (*ReportExecutionEventResponse) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{41} + return file_agent_agent_proto_rawDescGZIP(), []int{43} } func (x *ReportExecutionEventResponse) GetReceipt() *OperationReceipt { @@ -3941,7 +4071,7 @@ type RequestUploadRequest struct { func (x *RequestUploadRequest) Reset() { *x = RequestUploadRequest{} - mi := &file_agent_agent_proto_msgTypes[42] + mi := &file_agent_agent_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3953,7 +4083,7 @@ func (x *RequestUploadRequest) String() string { func (*RequestUploadRequest) ProtoMessage() {} func (x *RequestUploadRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[42] + mi := &file_agent_agent_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3966,7 +4096,7 @@ func (x *RequestUploadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestUploadRequest.ProtoReflect.Descriptor instead. func (*RequestUploadRequest) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{42} + return file_agent_agent_proto_rawDescGZIP(), []int{44} } func (x *RequestUploadRequest) GetMeta() *RequestMeta { @@ -4013,7 +4143,7 @@ type UploadGrant struct { func (x *UploadGrant) Reset() { *x = UploadGrant{} - mi := &file_agent_agent_proto_msgTypes[43] + mi := &file_agent_agent_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4025,7 +4155,7 @@ func (x *UploadGrant) String() string { func (*UploadGrant) ProtoMessage() {} func (x *UploadGrant) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[43] + mi := &file_agent_agent_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4038,7 +4168,7 @@ func (x *UploadGrant) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadGrant.ProtoReflect.Descriptor instead. func (*UploadGrant) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{43} + return file_agent_agent_proto_rawDescGZIP(), []int{45} } func (x *UploadGrant) GetUploadId() string { @@ -4108,7 +4238,7 @@ type RequestUploadResponse struct { func (x *RequestUploadResponse) Reset() { *x = RequestUploadResponse{} - mi := &file_agent_agent_proto_msgTypes[44] + mi := &file_agent_agent_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4120,7 +4250,7 @@ func (x *RequestUploadResponse) String() string { func (*RequestUploadResponse) ProtoMessage() {} func (x *RequestUploadResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[44] + mi := &file_agent_agent_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4133,7 +4263,7 @@ func (x *RequestUploadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestUploadResponse.ProtoReflect.Descriptor instead. func (*RequestUploadResponse) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{44} + return file_agent_agent_proto_rawDescGZIP(), []int{46} } func (x *RequestUploadResponse) GetReceipt() *OperationReceipt { @@ -4171,7 +4301,7 @@ type CompleteUploadRequest struct { func (x *CompleteUploadRequest) Reset() { *x = CompleteUploadRequest{} - mi := &file_agent_agent_proto_msgTypes[45] + mi := &file_agent_agent_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4183,7 +4313,7 @@ func (x *CompleteUploadRequest) String() string { func (*CompleteUploadRequest) ProtoMessage() {} func (x *CompleteUploadRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[45] + mi := &file_agent_agent_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4196,7 +4326,7 @@ func (x *CompleteUploadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CompleteUploadRequest.ProtoReflect.Descriptor instead. func (*CompleteUploadRequest) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{45} + return file_agent_agent_proto_rawDescGZIP(), []int{47} } func (x *CompleteUploadRequest) GetMeta() *RequestMeta { @@ -4251,7 +4381,7 @@ type CompleteUploadResponse struct { func (x *CompleteUploadResponse) Reset() { *x = CompleteUploadResponse{} - mi := &file_agent_agent_proto_msgTypes[46] + mi := &file_agent_agent_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4263,7 +4393,7 @@ func (x *CompleteUploadResponse) String() string { func (*CompleteUploadResponse) ProtoMessage() {} func (x *CompleteUploadResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[46] + mi := &file_agent_agent_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4276,7 +4406,7 @@ func (x *CompleteUploadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CompleteUploadResponse.ProtoReflect.Descriptor instead. func (*CompleteUploadResponse) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{46} + return file_agent_agent_proto_rawDescGZIP(), []int{48} } func (x *CompleteUploadResponse) GetReceipt() *OperationReceipt { @@ -4309,7 +4439,7 @@ type RequestRecordingUploadRequest struct { func (x *RequestRecordingUploadRequest) Reset() { *x = RequestRecordingUploadRequest{} - mi := &file_agent_agent_proto_msgTypes[47] + mi := &file_agent_agent_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4321,7 +4451,7 @@ func (x *RequestRecordingUploadRequest) String() string { func (*RequestRecordingUploadRequest) ProtoMessage() {} func (x *RequestRecordingUploadRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[47] + mi := &file_agent_agent_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4334,7 +4464,7 @@ func (x *RequestRecordingUploadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestRecordingUploadRequest.ProtoReflect.Descriptor instead. func (*RequestRecordingUploadRequest) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{47} + return file_agent_agent_proto_rawDescGZIP(), []int{49} } func (x *RequestRecordingUploadRequest) GetMeta() *RequestMeta { @@ -4388,7 +4518,7 @@ type RequestRecordingUploadResponse struct { func (x *RequestRecordingUploadResponse) Reset() { *x = RequestRecordingUploadResponse{} - mi := &file_agent_agent_proto_msgTypes[48] + mi := &file_agent_agent_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4400,7 +4530,7 @@ func (x *RequestRecordingUploadResponse) String() string { func (*RequestRecordingUploadResponse) ProtoMessage() {} func (x *RequestRecordingUploadResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[48] + mi := &file_agent_agent_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4413,7 +4543,7 @@ func (x *RequestRecordingUploadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestRecordingUploadResponse.ProtoReflect.Descriptor instead. func (*RequestRecordingUploadResponse) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{48} + return file_agent_agent_proto_rawDescGZIP(), []int{50} } func (x *RequestRecordingUploadResponse) GetGrant() *UploadGrant { @@ -4435,7 +4565,7 @@ type ReportCallEndedRequest struct { func (x *ReportCallEndedRequest) Reset() { *x = ReportCallEndedRequest{} - mi := &file_agent_agent_proto_msgTypes[49] + mi := &file_agent_agent_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4447,7 +4577,7 @@ func (x *ReportCallEndedRequest) String() string { func (*ReportCallEndedRequest) ProtoMessage() {} func (x *ReportCallEndedRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[49] + mi := &file_agent_agent_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4460,7 +4590,7 @@ func (x *ReportCallEndedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportCallEndedRequest.ProtoReflect.Descriptor instead. func (*ReportCallEndedRequest) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{49} + return file_agent_agent_proto_rawDescGZIP(), []int{51} } func (x *ReportCallEndedRequest) GetMeta() *RequestMeta { @@ -4500,7 +4630,7 @@ type ReportCallEndedResponse struct { func (x *ReportCallEndedResponse) Reset() { *x = ReportCallEndedResponse{} - mi := &file_agent_agent_proto_msgTypes[50] + mi := &file_agent_agent_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4512,7 +4642,7 @@ func (x *ReportCallEndedResponse) String() string { func (*ReportCallEndedResponse) ProtoMessage() {} func (x *ReportCallEndedResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[50] + mi := &file_agent_agent_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4525,7 +4655,7 @@ func (x *ReportCallEndedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportCallEndedResponse.ProtoReflect.Descriptor instead. func (*ReportCallEndedResponse) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{50} + return file_agent_agent_proto_rawDescGZIP(), []int{52} } func (x *ReportCallEndedResponse) GetReceipt() *OperationReceipt { @@ -4548,7 +4678,7 @@ type UploadObservation struct { func (x *UploadObservation) Reset() { *x = UploadObservation{} - mi := &file_agent_agent_proto_msgTypes[51] + mi := &file_agent_agent_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4560,7 +4690,7 @@ func (x *UploadObservation) String() string { func (*UploadObservation) ProtoMessage() {} func (x *UploadObservation) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[51] + mi := &file_agent_agent_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4573,7 +4703,7 @@ func (x *UploadObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadObservation.ProtoReflect.Descriptor instead. func (*UploadObservation) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{51} + return file_agent_agent_proto_rawDescGZIP(), []int{53} } func (x *UploadObservation) GetUploadId() string { @@ -4625,7 +4755,7 @@ type ReportCallResultRequest struct { func (x *ReportCallResultRequest) Reset() { *x = ReportCallResultRequest{} - mi := &file_agent_agent_proto_msgTypes[52] + mi := &file_agent_agent_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4637,7 +4767,7 @@ func (x *ReportCallResultRequest) String() string { func (*ReportCallResultRequest) ProtoMessage() {} func (x *ReportCallResultRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[52] + mi := &file_agent_agent_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4650,7 +4780,7 @@ func (x *ReportCallResultRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportCallResultRequest.ProtoReflect.Descriptor instead. func (*ReportCallResultRequest) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{52} + return file_agent_agent_proto_rawDescGZIP(), []int{54} } func (x *ReportCallResultRequest) GetMeta() *RequestMeta { @@ -4704,7 +4834,7 @@ type ReportCallResultResponse struct { func (x *ReportCallResultResponse) Reset() { *x = ReportCallResultResponse{} - mi := &file_agent_agent_proto_msgTypes[53] + mi := &file_agent_agent_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4716,7 +4846,7 @@ func (x *ReportCallResultResponse) String() string { func (*ReportCallResultResponse) ProtoMessage() {} func (x *ReportCallResultResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_agent_proto_msgTypes[53] + mi := &file_agent_agent_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4729,7 +4859,7 @@ func (x *ReportCallResultResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportCallResultResponse.ProtoReflect.Descriptor instead. func (*ReportCallResultResponse) Descriptor() ([]byte, []int) { - return file_agent_agent_proto_rawDescGZIP(), []int{53} + return file_agent_agent_proto_rawDescGZIP(), []int{55} } func (x *ReportCallResultResponse) GetReceipt() *OperationReceipt { @@ -5003,7 +5133,16 @@ const file_agent_agent_proto_rawDesc = "" + "\x18ApplyTaskControlResponse\x121\n" + "\areceipt\x18\x01 \x01(\v2\x17.agent.OperationReceiptR\areceipt\x122\n" + "\x15applied_task_revision\x18\x02 \x01(\x03R\x13appliedTaskRevision\x12+\n" + - "\x05state\x18\x03 \x01(\x0e2\x15.agent.ExecutionStateR\x05state\"r\n" + + "\x05state\x18\x03 \x01(\x0e2\x15.agent.ExecutionStateR\x05state\"\x99\x02\n" + + "\x1fApplyApprovedTaskControlRequest\x12&\n" + + "\x04meta\x18\x01 \x01(\v2\x12.agent.RequestMetaR\x04meta\x12#\n" + + "\rdispatcher_id\x18\x02 \x01(\tR\fdispatcherId\x12\x1b\n" + + "\ttenant_id\x18\x03 \x01(\x03R\btenantId\x12\x17\n" + + "\atask_id\x18\x04 \x01(\tR\x06taskId\x12,\n" + + "\x06action\x18\x05 \x01(\x0e2\x14.agent.ControlActionR\x06action\x12E\n" + + "\x12active_call_policy\x18\x06 \x01(\x0e2\x17.agent.ActiveCallPolicyR\x10activeCallPolicy\">\n" + + " ApplyApprovedTaskControlResponse\x12\x1a\n" + + "\baccepted\x18\x01 \x01(\bR\baccepted\"r\n" + "\x15QueryExecutionRequest\x12&\n" + "\x04meta\x18\x01 \x01(\v2\x12.agent.RequestMetaR\x04meta\x121\n" + "\abinding\x18\x02 \x01(\v2\x17.agent.ExecutionBindingR\abinding\"\xcb\x02\n" + @@ -5166,7 +5305,7 @@ const file_agent_agent_proto_rawDesc = "" + "\x1cFACT_KIND_TRANSCRIPT_UPDATED\x10\x04\x12\x1f\n" + "\x1bFACT_KIND_TRANSCRIPT_FAILED\x10\x05\x12\x1d\n" + "\x19FACT_KIND_CONTACT_OPT_OUT\x10\x06\x12 \n" + - "\x1cFACT_KIND_RECORDING_PROGRESS\x10\a2\x87\v\n" + + "\x1cFACT_KIND_RECORDING_PROGRESS\x10\a2\xf4\v\n" + "\x13AgentControlService\x12M\n" + "\x0eGetAgentStatus\x12\x1c.agent.GetAgentStatusRequest\x1a\x1d.agent.GetAgentStatusResponse\x12J\n" + "\rActivateAgent\x12\x1b.agent.ActivateAgentRequest\x1a\x1c.agent.ActivateAgentResponse\x12G\n" + @@ -5174,7 +5313,8 @@ const file_agent_agent_proto_rawDesc = "" + "\x11SetAdmissionState\x12\x1f.agent.SetAdmissionStateRequest\x1a .agent.SetAdmissionStateResponse\x128\n" + "\aExecute\x12\x15.agent.ExecuteRequest\x1a\x16.agent.ExecuteResponse\x12V\n" + "\x11ExecuteAuthorized\x12\x1f.agent.ExecuteAuthorizedRequest\x1a .agent.ExecuteAuthorizedResponse\x12P\n" + - "\x0fExecuteApproved\x12\x1d.agent.ExecuteApprovedRequest\x1a\x1e.agent.ExecuteApprovedResponse\x12G\n" + + "\x0fExecuteApproved\x12\x1d.agent.ExecuteApprovedRequest\x1a\x1e.agent.ExecuteApprovedResponse\x12k\n" + + "\x18ApplyApprovedTaskControl\x12&.agent.ApplyApprovedTaskControlRequest\x1a'.agent.ApplyApprovedTaskControlResponse\x12G\n" + "\fGetLoadedSIP\x12\x1a.agent.GetLoadedSIPRequest\x1a\x1b.agent.GetLoadedSIPResponse\x12Y\n" + "\x12GetExecutionPermit\x12 .agent.GetExecutionPermitRequest\x1a!.agent.GetExecutionPermitResponse\x12S\n" + "\x10ApplyTaskControl\x12\x1e.agent.ApplyTaskControlRequest\x1a\x1f.agent.ApplyTaskControlResponse\x12M\n" + @@ -5199,73 +5339,75 @@ func file_agent_agent_proto_rawDescGZIP() []byte { } var file_agent_agent_proto_enumTypes = make([]protoimpl.EnumInfo, 10) -var file_agent_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 55) +var file_agent_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 57) var file_agent_agent_proto_goTypes = []any{ - (ResultCode)(0), // 0: agent.ResultCode - (FailureCode)(0), // 1: agent.FailureCode - (ActivationState)(0), // 2: agent.ActivationState - (AdmissionState)(0), // 3: agent.AdmissionState - (ControlAction)(0), // 4: agent.ControlAction - (ActiveCallPolicy)(0), // 5: agent.ActiveCallPolicy - (ExecutionState)(0), // 6: agent.ExecutionState - (AssetKind)(0), // 7: agent.AssetKind - (UploadState)(0), // 8: agent.UploadState - (FactKind)(0), // 9: agent.FactKind - (*RequestMeta)(nil), // 10: agent.RequestMeta - (*ResponseMeta)(nil), // 11: agent.ResponseMeta - (*Failure)(nil), // 12: agent.Failure - (*OperationReceipt)(nil), // 13: agent.OperationReceipt - (*AgentBinding)(nil), // 14: agent.AgentBinding - (*Capability)(nil), // 15: agent.Capability - (*ResourceSample)(nil), // 16: agent.ResourceSample - (*AppliedConfig)(nil), // 17: agent.AppliedConfig - (*AgentStatus)(nil), // 18: agent.AgentStatus - (*Session)(nil), // 19: agent.Session - (*ConfigReference)(nil), // 20: agent.ConfigReference - (*UploadPolicy)(nil), // 21: agent.UploadPolicy - (*ExecutionBinding)(nil), // 22: agent.ExecutionBinding - (*AssetDescriptor)(nil), // 23: agent.AssetDescriptor - (*Header)(nil), // 24: agent.Header - (*GetAgentStatusRequest)(nil), // 25: agent.GetAgentStatusRequest - (*GetAgentStatusResponse)(nil), // 26: agent.GetAgentStatusResponse - (*ActivateAgentRequest)(nil), // 27: agent.ActivateAgentRequest - (*ActivateAgentResponse)(nil), // 28: agent.ActivateAgentResponse - (*GetBootstrapRequest)(nil), // 29: agent.GetBootstrapRequest - (*GetBootstrapResponse)(nil), // 30: agent.GetBootstrapResponse - (*SetAdmissionStateRequest)(nil), // 31: agent.SetAdmissionStateRequest - (*SetAdmissionStateResponse)(nil), // 32: agent.SetAdmissionStateResponse - (*ExecuteRequest)(nil), // 33: agent.ExecuteRequest - (*ExecuteResponse)(nil), // 34: agent.ExecuteResponse - (*ExecuteAuthorizedRequest)(nil), // 35: agent.ExecuteAuthorizedRequest - (*ExecuteAuthorizedResponse)(nil), // 36: agent.ExecuteAuthorizedResponse - (*ExecuteApprovedRequest)(nil), // 37: agent.ExecuteApprovedRequest - (*ExecuteApprovedResponse)(nil), // 38: agent.ExecuteApprovedResponse - (*GetLoadedSIPRequest)(nil), // 39: agent.GetLoadedSIPRequest - (*GetLoadedSIPResponse)(nil), // 40: agent.GetLoadedSIPResponse - (*GetExecutionPermitRequest)(nil), // 41: agent.GetExecutionPermitRequest - (*ExecutionPermit)(nil), // 42: agent.ExecutionPermit - (*GetExecutionPermitResponse)(nil), // 43: agent.GetExecutionPermitResponse - (*ApplyTaskControlRequest)(nil), // 44: agent.ApplyTaskControlRequest - (*ApplyTaskControlResponse)(nil), // 45: agent.ApplyTaskControlResponse - (*QueryExecutionRequest)(nil), // 46: agent.QueryExecutionRequest - (*ExecutionSnapshot)(nil), // 47: agent.ExecutionSnapshot - (*QueryExecutionResponse)(nil), // 48: agent.QueryExecutionResponse - (*ExecutionFact)(nil), // 49: agent.ExecutionFact - (*ReportExecutionEventRequest)(nil), // 50: agent.ReportExecutionEventRequest - (*ReportExecutionEventResponse)(nil), // 51: agent.ReportExecutionEventResponse - (*RequestUploadRequest)(nil), // 52: agent.RequestUploadRequest - (*UploadGrant)(nil), // 53: agent.UploadGrant - (*RequestUploadResponse)(nil), // 54: agent.RequestUploadResponse - (*CompleteUploadRequest)(nil), // 55: agent.CompleteUploadRequest - (*CompleteUploadResponse)(nil), // 56: agent.CompleteUploadResponse - (*RequestRecordingUploadRequest)(nil), // 57: agent.RequestRecordingUploadRequest - (*RequestRecordingUploadResponse)(nil), // 58: agent.RequestRecordingUploadResponse - (*ReportCallEndedRequest)(nil), // 59: agent.ReportCallEndedRequest - (*ReportCallEndedResponse)(nil), // 60: agent.ReportCallEndedResponse - (*UploadObservation)(nil), // 61: agent.UploadObservation - (*ReportCallResultRequest)(nil), // 62: agent.ReportCallResultRequest - (*ReportCallResultResponse)(nil), // 63: agent.ReportCallResultResponse - nil, // 64: agent.GetLoadedSIPResponse.TrunkRevisionEntry + (ResultCode)(0), // 0: agent.ResultCode + (FailureCode)(0), // 1: agent.FailureCode + (ActivationState)(0), // 2: agent.ActivationState + (AdmissionState)(0), // 3: agent.AdmissionState + (ControlAction)(0), // 4: agent.ControlAction + (ActiveCallPolicy)(0), // 5: agent.ActiveCallPolicy + (ExecutionState)(0), // 6: agent.ExecutionState + (AssetKind)(0), // 7: agent.AssetKind + (UploadState)(0), // 8: agent.UploadState + (FactKind)(0), // 9: agent.FactKind + (*RequestMeta)(nil), // 10: agent.RequestMeta + (*ResponseMeta)(nil), // 11: agent.ResponseMeta + (*Failure)(nil), // 12: agent.Failure + (*OperationReceipt)(nil), // 13: agent.OperationReceipt + (*AgentBinding)(nil), // 14: agent.AgentBinding + (*Capability)(nil), // 15: agent.Capability + (*ResourceSample)(nil), // 16: agent.ResourceSample + (*AppliedConfig)(nil), // 17: agent.AppliedConfig + (*AgentStatus)(nil), // 18: agent.AgentStatus + (*Session)(nil), // 19: agent.Session + (*ConfigReference)(nil), // 20: agent.ConfigReference + (*UploadPolicy)(nil), // 21: agent.UploadPolicy + (*ExecutionBinding)(nil), // 22: agent.ExecutionBinding + (*AssetDescriptor)(nil), // 23: agent.AssetDescriptor + (*Header)(nil), // 24: agent.Header + (*GetAgentStatusRequest)(nil), // 25: agent.GetAgentStatusRequest + (*GetAgentStatusResponse)(nil), // 26: agent.GetAgentStatusResponse + (*ActivateAgentRequest)(nil), // 27: agent.ActivateAgentRequest + (*ActivateAgentResponse)(nil), // 28: agent.ActivateAgentResponse + (*GetBootstrapRequest)(nil), // 29: agent.GetBootstrapRequest + (*GetBootstrapResponse)(nil), // 30: agent.GetBootstrapResponse + (*SetAdmissionStateRequest)(nil), // 31: agent.SetAdmissionStateRequest + (*SetAdmissionStateResponse)(nil), // 32: agent.SetAdmissionStateResponse + (*ExecuteRequest)(nil), // 33: agent.ExecuteRequest + (*ExecuteResponse)(nil), // 34: agent.ExecuteResponse + (*ExecuteAuthorizedRequest)(nil), // 35: agent.ExecuteAuthorizedRequest + (*ExecuteAuthorizedResponse)(nil), // 36: agent.ExecuteAuthorizedResponse + (*ExecuteApprovedRequest)(nil), // 37: agent.ExecuteApprovedRequest + (*ExecuteApprovedResponse)(nil), // 38: agent.ExecuteApprovedResponse + (*GetLoadedSIPRequest)(nil), // 39: agent.GetLoadedSIPRequest + (*GetLoadedSIPResponse)(nil), // 40: agent.GetLoadedSIPResponse + (*GetExecutionPermitRequest)(nil), // 41: agent.GetExecutionPermitRequest + (*ExecutionPermit)(nil), // 42: agent.ExecutionPermit + (*GetExecutionPermitResponse)(nil), // 43: agent.GetExecutionPermitResponse + (*ApplyTaskControlRequest)(nil), // 44: agent.ApplyTaskControlRequest + (*ApplyTaskControlResponse)(nil), // 45: agent.ApplyTaskControlResponse + (*ApplyApprovedTaskControlRequest)(nil), // 46: agent.ApplyApprovedTaskControlRequest + (*ApplyApprovedTaskControlResponse)(nil), // 47: agent.ApplyApprovedTaskControlResponse + (*QueryExecutionRequest)(nil), // 48: agent.QueryExecutionRequest + (*ExecutionSnapshot)(nil), // 49: agent.ExecutionSnapshot + (*QueryExecutionResponse)(nil), // 50: agent.QueryExecutionResponse + (*ExecutionFact)(nil), // 51: agent.ExecutionFact + (*ReportExecutionEventRequest)(nil), // 52: agent.ReportExecutionEventRequest + (*ReportExecutionEventResponse)(nil), // 53: agent.ReportExecutionEventResponse + (*RequestUploadRequest)(nil), // 54: agent.RequestUploadRequest + (*UploadGrant)(nil), // 55: agent.UploadGrant + (*RequestUploadResponse)(nil), // 56: agent.RequestUploadResponse + (*CompleteUploadRequest)(nil), // 57: agent.CompleteUploadRequest + (*CompleteUploadResponse)(nil), // 58: agent.CompleteUploadResponse + (*RequestRecordingUploadRequest)(nil), // 59: agent.RequestRecordingUploadRequest + (*RequestRecordingUploadResponse)(nil), // 60: agent.RequestRecordingUploadResponse + (*ReportCallEndedRequest)(nil), // 61: agent.ReportCallEndedRequest + (*ReportCallEndedResponse)(nil), // 62: agent.ReportCallEndedResponse + (*UploadObservation)(nil), // 63: agent.UploadObservation + (*ReportCallResultRequest)(nil), // 64: agent.ReportCallResultRequest + (*ReportCallResultResponse)(nil), // 65: agent.ReportCallResultResponse + nil, // 66: agent.GetLoadedSIPResponse.TrunkRevisionEntry } var file_agent_agent_proto_depIdxs = []int32{ 1, // 0: agent.Failure.code:type_name -> agent.FailureCode @@ -5308,7 +5450,7 @@ var file_agent_agent_proto_depIdxs = []int32{ 6, // 37: agent.ExecuteAuthorizedResponse.state:type_name -> agent.ExecutionState 10, // 38: agent.ExecuteApprovedRequest.meta:type_name -> agent.RequestMeta 10, // 39: agent.GetLoadedSIPRequest.meta:type_name -> agent.RequestMeta - 64, // 40: agent.GetLoadedSIPResponse.trunk_revision:type_name -> agent.GetLoadedSIPResponse.TrunkRevisionEntry + 66, // 40: agent.GetLoadedSIPResponse.trunk_revision:type_name -> agent.GetLoadedSIPResponse.TrunkRevisionEntry 10, // 41: agent.GetExecutionPermitRequest.meta:type_name -> agent.RequestMeta 22, // 42: agent.GetExecutionPermitRequest.binding:type_name -> agent.ExecutionBinding 13, // 43: agent.GetExecutionPermitResponse.receipt:type_name -> agent.OperationReceipt @@ -5319,78 +5461,83 @@ var file_agent_agent_proto_depIdxs = []int32{ 5, // 48: agent.ApplyTaskControlRequest.active_call_policy:type_name -> agent.ActiveCallPolicy 13, // 49: agent.ApplyTaskControlResponse.receipt:type_name -> agent.OperationReceipt 6, // 50: agent.ApplyTaskControlResponse.state:type_name -> agent.ExecutionState - 10, // 51: agent.QueryExecutionRequest.meta:type_name -> agent.RequestMeta - 22, // 52: agent.QueryExecutionRequest.binding:type_name -> agent.ExecutionBinding - 22, // 53: agent.ExecutionSnapshot.binding:type_name -> agent.ExecutionBinding - 6, // 54: agent.ExecutionSnapshot.state:type_name -> agent.ExecutionState - 23, // 55: agent.ExecutionSnapshot.assets:type_name -> agent.AssetDescriptor - 11, // 56: agent.QueryExecutionResponse.meta:type_name -> agent.ResponseMeta - 47, // 57: agent.QueryExecutionResponse.snapshot:type_name -> agent.ExecutionSnapshot - 12, // 58: agent.QueryExecutionResponse.failure:type_name -> agent.Failure - 22, // 59: agent.ExecutionFact.binding:type_name -> agent.ExecutionBinding - 9, // 60: agent.ExecutionFact.kind:type_name -> agent.FactKind - 10, // 61: agent.ReportExecutionEventRequest.meta:type_name -> agent.RequestMeta - 49, // 62: agent.ReportExecutionEventRequest.fact:type_name -> agent.ExecutionFact - 13, // 63: agent.ReportExecutionEventResponse.receipt:type_name -> agent.OperationReceipt - 10, // 64: agent.RequestUploadRequest.meta:type_name -> agent.RequestMeta - 22, // 65: agent.RequestUploadRequest.binding:type_name -> agent.ExecutionBinding - 23, // 66: agent.RequestUploadRequest.asset:type_name -> agent.AssetDescriptor - 24, // 67: agent.UploadGrant.headers:type_name -> agent.Header - 13, // 68: agent.RequestUploadResponse.receipt:type_name -> agent.OperationReceipt - 53, // 69: agent.RequestUploadResponse.grant:type_name -> agent.UploadGrant - 8, // 70: agent.RequestUploadResponse.state:type_name -> agent.UploadState - 10, // 71: agent.CompleteUploadRequest.meta:type_name -> agent.RequestMeta - 22, // 72: agent.CompleteUploadRequest.binding:type_name -> agent.ExecutionBinding - 23, // 73: agent.CompleteUploadRequest.asset:type_name -> agent.AssetDescriptor - 13, // 74: agent.CompleteUploadResponse.receipt:type_name -> agent.OperationReceipt - 8, // 75: agent.CompleteUploadResponse.state:type_name -> agent.UploadState - 10, // 76: agent.RequestRecordingUploadRequest.meta:type_name -> agent.RequestMeta - 23, // 77: agent.RequestRecordingUploadRequest.asset:type_name -> agent.AssetDescriptor - 53, // 78: agent.RequestRecordingUploadResponse.grant:type_name -> agent.UploadGrant - 10, // 79: agent.ReportCallEndedRequest.meta:type_name -> agent.RequestMeta - 13, // 80: agent.ReportCallEndedResponse.receipt:type_name -> agent.OperationReceipt - 10, // 81: agent.ReportCallResultRequest.meta:type_name -> agent.RequestMeta - 61, // 82: agent.ReportCallResultRequest.upload:type_name -> agent.UploadObservation - 13, // 83: agent.ReportCallResultResponse.receipt:type_name -> agent.OperationReceipt - 25, // 84: agent.AgentControlService.GetAgentStatus:input_type -> agent.GetAgentStatusRequest - 27, // 85: agent.AgentControlService.ActivateAgent:input_type -> agent.ActivateAgentRequest - 29, // 86: agent.AgentControlService.GetBootstrap:input_type -> agent.GetBootstrapRequest - 31, // 87: agent.AgentControlService.SetAdmissionState:input_type -> agent.SetAdmissionStateRequest - 33, // 88: agent.AgentControlService.Execute:input_type -> agent.ExecuteRequest - 35, // 89: agent.AgentControlService.ExecuteAuthorized:input_type -> agent.ExecuteAuthorizedRequest - 37, // 90: agent.AgentControlService.ExecuteApproved:input_type -> agent.ExecuteApprovedRequest - 39, // 91: agent.AgentControlService.GetLoadedSIP:input_type -> agent.GetLoadedSIPRequest - 41, // 92: agent.AgentControlService.GetExecutionPermit:input_type -> agent.GetExecutionPermitRequest - 44, // 93: agent.AgentControlService.ApplyTaskControl:input_type -> agent.ApplyTaskControlRequest - 46, // 94: agent.AgentControlService.QueryExecution:input_type -> agent.QueryExecutionRequest - 50, // 95: agent.AgentControlService.ReportExecutionEvent:input_type -> agent.ReportExecutionEventRequest - 52, // 96: agent.AgentControlService.RequestUpload:input_type -> agent.RequestUploadRequest - 55, // 97: agent.AgentControlService.CompleteUpload:input_type -> agent.CompleteUploadRequest - 57, // 98: agent.AgentControlService.RequestRecordingUpload:input_type -> agent.RequestRecordingUploadRequest - 59, // 99: agent.AgentControlService.ReportCallEnded:input_type -> agent.ReportCallEndedRequest - 62, // 100: agent.AgentControlService.ReportCallResult:input_type -> agent.ReportCallResultRequest - 26, // 101: agent.AgentControlService.GetAgentStatus:output_type -> agent.GetAgentStatusResponse - 28, // 102: agent.AgentControlService.ActivateAgent:output_type -> agent.ActivateAgentResponse - 30, // 103: agent.AgentControlService.GetBootstrap:output_type -> agent.GetBootstrapResponse - 32, // 104: agent.AgentControlService.SetAdmissionState:output_type -> agent.SetAdmissionStateResponse - 34, // 105: agent.AgentControlService.Execute:output_type -> agent.ExecuteResponse - 36, // 106: agent.AgentControlService.ExecuteAuthorized:output_type -> agent.ExecuteAuthorizedResponse - 38, // 107: agent.AgentControlService.ExecuteApproved:output_type -> agent.ExecuteApprovedResponse - 40, // 108: agent.AgentControlService.GetLoadedSIP:output_type -> agent.GetLoadedSIPResponse - 43, // 109: agent.AgentControlService.GetExecutionPermit:output_type -> agent.GetExecutionPermitResponse - 45, // 110: agent.AgentControlService.ApplyTaskControl:output_type -> agent.ApplyTaskControlResponse - 48, // 111: agent.AgentControlService.QueryExecution:output_type -> agent.QueryExecutionResponse - 51, // 112: agent.AgentControlService.ReportExecutionEvent:output_type -> agent.ReportExecutionEventResponse - 54, // 113: agent.AgentControlService.RequestUpload:output_type -> agent.RequestUploadResponse - 56, // 114: agent.AgentControlService.CompleteUpload:output_type -> agent.CompleteUploadResponse - 58, // 115: agent.AgentControlService.RequestRecordingUpload:output_type -> agent.RequestRecordingUploadResponse - 60, // 116: agent.AgentControlService.ReportCallEnded:output_type -> agent.ReportCallEndedResponse - 63, // 117: agent.AgentControlService.ReportCallResult:output_type -> agent.ReportCallResultResponse - 101, // [101:118] is the sub-list for method output_type - 84, // [84:101] is the sub-list for method input_type - 84, // [84:84] is the sub-list for extension type_name - 84, // [84:84] is the sub-list for extension extendee - 0, // [0:84] is the sub-list for field type_name + 10, // 51: agent.ApplyApprovedTaskControlRequest.meta:type_name -> agent.RequestMeta + 4, // 52: agent.ApplyApprovedTaskControlRequest.action:type_name -> agent.ControlAction + 5, // 53: agent.ApplyApprovedTaskControlRequest.active_call_policy:type_name -> agent.ActiveCallPolicy + 10, // 54: agent.QueryExecutionRequest.meta:type_name -> agent.RequestMeta + 22, // 55: agent.QueryExecutionRequest.binding:type_name -> agent.ExecutionBinding + 22, // 56: agent.ExecutionSnapshot.binding:type_name -> agent.ExecutionBinding + 6, // 57: agent.ExecutionSnapshot.state:type_name -> agent.ExecutionState + 23, // 58: agent.ExecutionSnapshot.assets:type_name -> agent.AssetDescriptor + 11, // 59: agent.QueryExecutionResponse.meta:type_name -> agent.ResponseMeta + 49, // 60: agent.QueryExecutionResponse.snapshot:type_name -> agent.ExecutionSnapshot + 12, // 61: agent.QueryExecutionResponse.failure:type_name -> agent.Failure + 22, // 62: agent.ExecutionFact.binding:type_name -> agent.ExecutionBinding + 9, // 63: agent.ExecutionFact.kind:type_name -> agent.FactKind + 10, // 64: agent.ReportExecutionEventRequest.meta:type_name -> agent.RequestMeta + 51, // 65: agent.ReportExecutionEventRequest.fact:type_name -> agent.ExecutionFact + 13, // 66: agent.ReportExecutionEventResponse.receipt:type_name -> agent.OperationReceipt + 10, // 67: agent.RequestUploadRequest.meta:type_name -> agent.RequestMeta + 22, // 68: agent.RequestUploadRequest.binding:type_name -> agent.ExecutionBinding + 23, // 69: agent.RequestUploadRequest.asset:type_name -> agent.AssetDescriptor + 24, // 70: agent.UploadGrant.headers:type_name -> agent.Header + 13, // 71: agent.RequestUploadResponse.receipt:type_name -> agent.OperationReceipt + 55, // 72: agent.RequestUploadResponse.grant:type_name -> agent.UploadGrant + 8, // 73: agent.RequestUploadResponse.state:type_name -> agent.UploadState + 10, // 74: agent.CompleteUploadRequest.meta:type_name -> agent.RequestMeta + 22, // 75: agent.CompleteUploadRequest.binding:type_name -> agent.ExecutionBinding + 23, // 76: agent.CompleteUploadRequest.asset:type_name -> agent.AssetDescriptor + 13, // 77: agent.CompleteUploadResponse.receipt:type_name -> agent.OperationReceipt + 8, // 78: agent.CompleteUploadResponse.state:type_name -> agent.UploadState + 10, // 79: agent.RequestRecordingUploadRequest.meta:type_name -> agent.RequestMeta + 23, // 80: agent.RequestRecordingUploadRequest.asset:type_name -> agent.AssetDescriptor + 55, // 81: agent.RequestRecordingUploadResponse.grant:type_name -> agent.UploadGrant + 10, // 82: agent.ReportCallEndedRequest.meta:type_name -> agent.RequestMeta + 13, // 83: agent.ReportCallEndedResponse.receipt:type_name -> agent.OperationReceipt + 10, // 84: agent.ReportCallResultRequest.meta:type_name -> agent.RequestMeta + 63, // 85: agent.ReportCallResultRequest.upload:type_name -> agent.UploadObservation + 13, // 86: agent.ReportCallResultResponse.receipt:type_name -> agent.OperationReceipt + 25, // 87: agent.AgentControlService.GetAgentStatus:input_type -> agent.GetAgentStatusRequest + 27, // 88: agent.AgentControlService.ActivateAgent:input_type -> agent.ActivateAgentRequest + 29, // 89: agent.AgentControlService.GetBootstrap:input_type -> agent.GetBootstrapRequest + 31, // 90: agent.AgentControlService.SetAdmissionState:input_type -> agent.SetAdmissionStateRequest + 33, // 91: agent.AgentControlService.Execute:input_type -> agent.ExecuteRequest + 35, // 92: agent.AgentControlService.ExecuteAuthorized:input_type -> agent.ExecuteAuthorizedRequest + 37, // 93: agent.AgentControlService.ExecuteApproved:input_type -> agent.ExecuteApprovedRequest + 46, // 94: agent.AgentControlService.ApplyApprovedTaskControl:input_type -> agent.ApplyApprovedTaskControlRequest + 39, // 95: agent.AgentControlService.GetLoadedSIP:input_type -> agent.GetLoadedSIPRequest + 41, // 96: agent.AgentControlService.GetExecutionPermit:input_type -> agent.GetExecutionPermitRequest + 44, // 97: agent.AgentControlService.ApplyTaskControl:input_type -> agent.ApplyTaskControlRequest + 48, // 98: agent.AgentControlService.QueryExecution:input_type -> agent.QueryExecutionRequest + 52, // 99: agent.AgentControlService.ReportExecutionEvent:input_type -> agent.ReportExecutionEventRequest + 54, // 100: agent.AgentControlService.RequestUpload:input_type -> agent.RequestUploadRequest + 57, // 101: agent.AgentControlService.CompleteUpload:input_type -> agent.CompleteUploadRequest + 59, // 102: agent.AgentControlService.RequestRecordingUpload:input_type -> agent.RequestRecordingUploadRequest + 61, // 103: agent.AgentControlService.ReportCallEnded:input_type -> agent.ReportCallEndedRequest + 64, // 104: agent.AgentControlService.ReportCallResult:input_type -> agent.ReportCallResultRequest + 26, // 105: agent.AgentControlService.GetAgentStatus:output_type -> agent.GetAgentStatusResponse + 28, // 106: agent.AgentControlService.ActivateAgent:output_type -> agent.ActivateAgentResponse + 30, // 107: agent.AgentControlService.GetBootstrap:output_type -> agent.GetBootstrapResponse + 32, // 108: agent.AgentControlService.SetAdmissionState:output_type -> agent.SetAdmissionStateResponse + 34, // 109: agent.AgentControlService.Execute:output_type -> agent.ExecuteResponse + 36, // 110: agent.AgentControlService.ExecuteAuthorized:output_type -> agent.ExecuteAuthorizedResponse + 38, // 111: agent.AgentControlService.ExecuteApproved:output_type -> agent.ExecuteApprovedResponse + 47, // 112: agent.AgentControlService.ApplyApprovedTaskControl:output_type -> agent.ApplyApprovedTaskControlResponse + 40, // 113: agent.AgentControlService.GetLoadedSIP:output_type -> agent.GetLoadedSIPResponse + 43, // 114: agent.AgentControlService.GetExecutionPermit:output_type -> agent.GetExecutionPermitResponse + 45, // 115: agent.AgentControlService.ApplyTaskControl:output_type -> agent.ApplyTaskControlResponse + 50, // 116: agent.AgentControlService.QueryExecution:output_type -> agent.QueryExecutionResponse + 53, // 117: agent.AgentControlService.ReportExecutionEvent:output_type -> agent.ReportExecutionEventResponse + 56, // 118: agent.AgentControlService.RequestUpload:output_type -> agent.RequestUploadResponse + 58, // 119: agent.AgentControlService.CompleteUpload:output_type -> agent.CompleteUploadResponse + 60, // 120: agent.AgentControlService.RequestRecordingUpload:output_type -> agent.RequestRecordingUploadResponse + 62, // 121: agent.AgentControlService.ReportCallEnded:output_type -> agent.ReportCallEndedResponse + 65, // 122: agent.AgentControlService.ReportCallResult:output_type -> agent.ReportCallResultResponse + 105, // [105:123] is the sub-list for method output_type + 87, // [87:105] is the sub-list for method input_type + 87, // [87:87] is the sub-list for extension type_name + 87, // [87:87] is the sub-list for extension extendee + 0, // [0:87] is the sub-list for field type_name } func init() { file_agent_agent_proto_init() } @@ -5404,7 +5551,7 @@ func file_agent_agent_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_agent_agent_proto_rawDesc), len(file_agent_agent_proto_rawDesc)), NumEnums: 10, - NumMessages: 55, + NumMessages: 57, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/agent/agent_grpc.pb.go b/gen/agent/agent_grpc.pb.go index 23b9c5d..3f07e20 100644 --- a/gen/agent/agent_grpc.pb.go +++ b/gen/agent/agent_grpc.pb.go @@ -19,23 +19,24 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - AgentControlService_GetAgentStatus_FullMethodName = "/agent.AgentControlService/GetAgentStatus" - AgentControlService_ActivateAgent_FullMethodName = "/agent.AgentControlService/ActivateAgent" - AgentControlService_GetBootstrap_FullMethodName = "/agent.AgentControlService/GetBootstrap" - AgentControlService_SetAdmissionState_FullMethodName = "/agent.AgentControlService/SetAdmissionState" - AgentControlService_Execute_FullMethodName = "/agent.AgentControlService/Execute" - AgentControlService_ExecuteAuthorized_FullMethodName = "/agent.AgentControlService/ExecuteAuthorized" - AgentControlService_ExecuteApproved_FullMethodName = "/agent.AgentControlService/ExecuteApproved" - AgentControlService_GetLoadedSIP_FullMethodName = "/agent.AgentControlService/GetLoadedSIP" - AgentControlService_GetExecutionPermit_FullMethodName = "/agent.AgentControlService/GetExecutionPermit" - AgentControlService_ApplyTaskControl_FullMethodName = "/agent.AgentControlService/ApplyTaskControl" - AgentControlService_QueryExecution_FullMethodName = "/agent.AgentControlService/QueryExecution" - AgentControlService_ReportExecutionEvent_FullMethodName = "/agent.AgentControlService/ReportExecutionEvent" - AgentControlService_RequestUpload_FullMethodName = "/agent.AgentControlService/RequestUpload" - AgentControlService_CompleteUpload_FullMethodName = "/agent.AgentControlService/CompleteUpload" - AgentControlService_RequestRecordingUpload_FullMethodName = "/agent.AgentControlService/RequestRecordingUpload" - AgentControlService_ReportCallEnded_FullMethodName = "/agent.AgentControlService/ReportCallEnded" - AgentControlService_ReportCallResult_FullMethodName = "/agent.AgentControlService/ReportCallResult" + AgentControlService_GetAgentStatus_FullMethodName = "/agent.AgentControlService/GetAgentStatus" + AgentControlService_ActivateAgent_FullMethodName = "/agent.AgentControlService/ActivateAgent" + AgentControlService_GetBootstrap_FullMethodName = "/agent.AgentControlService/GetBootstrap" + AgentControlService_SetAdmissionState_FullMethodName = "/agent.AgentControlService/SetAdmissionState" + AgentControlService_Execute_FullMethodName = "/agent.AgentControlService/Execute" + AgentControlService_ExecuteAuthorized_FullMethodName = "/agent.AgentControlService/ExecuteAuthorized" + AgentControlService_ExecuteApproved_FullMethodName = "/agent.AgentControlService/ExecuteApproved" + AgentControlService_ApplyApprovedTaskControl_FullMethodName = "/agent.AgentControlService/ApplyApprovedTaskControl" + AgentControlService_GetLoadedSIP_FullMethodName = "/agent.AgentControlService/GetLoadedSIP" + AgentControlService_GetExecutionPermit_FullMethodName = "/agent.AgentControlService/GetExecutionPermit" + AgentControlService_ApplyTaskControl_FullMethodName = "/agent.AgentControlService/ApplyTaskControl" + AgentControlService_QueryExecution_FullMethodName = "/agent.AgentControlService/QueryExecution" + AgentControlService_ReportExecutionEvent_FullMethodName = "/agent.AgentControlService/ReportExecutionEvent" + AgentControlService_RequestUpload_FullMethodName = "/agent.AgentControlService/RequestUpload" + AgentControlService_CompleteUpload_FullMethodName = "/agent.AgentControlService/CompleteUpload" + AgentControlService_RequestRecordingUpload_FullMethodName = "/agent.AgentControlService/RequestRecordingUpload" + AgentControlService_ReportCallEnded_FullMethodName = "/agent.AgentControlService/ReportCallEnded" + AgentControlService_ReportCallResult_FullMethodName = "/agent.AgentControlService/ReportCallResult" ) // AgentControlServiceClient is the client API for AgentControlService service. @@ -54,6 +55,7 @@ type AgentControlServiceClient interface { // Local P1 Mock: accepts a Dispatcher-authorized, immutable dial decision. ExecuteAuthorized(ctx context.Context, in *ExecuteAuthorizedRequest, opts ...grpc.CallOption) (*ExecuteAuthorizedResponse, error) ExecuteApproved(ctx context.Context, in *ExecuteApprovedRequest, opts ...grpc.CallOption) (*ExecuteApprovedResponse, error) + ApplyApprovedTaskControl(ctx context.Context, in *ApplyApprovedTaskControlRequest, opts ...grpc.CallOption) (*ApplyApprovedTaskControlResponse, error) GetLoadedSIP(ctx context.Context, in *GetLoadedSIPRequest, opts ...grpc.CallOption) (*GetLoadedSIPResponse, error) GetExecutionPermit(ctx context.Context, in *GetExecutionPermitRequest, opts ...grpc.CallOption) (*GetExecutionPermitResponse, error) ApplyTaskControl(ctx context.Context, in *ApplyTaskControlRequest, opts ...grpc.CallOption) (*ApplyTaskControlResponse, error) @@ -145,6 +147,16 @@ func (c *agentControlServiceClient) ExecuteApproved(ctx context.Context, in *Exe return out, nil } +func (c *agentControlServiceClient) ApplyApprovedTaskControl(ctx context.Context, in *ApplyApprovedTaskControlRequest, opts ...grpc.CallOption) (*ApplyApprovedTaskControlResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ApplyApprovedTaskControlResponse) + err := c.cc.Invoke(ctx, AgentControlService_ApplyApprovedTaskControl_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *agentControlServiceClient) GetLoadedSIP(ctx context.Context, in *GetLoadedSIPRequest, opts ...grpc.CallOption) (*GetLoadedSIPResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetLoadedSIPResponse) @@ -261,6 +273,7 @@ type AgentControlServiceServer interface { // Local P1 Mock: accepts a Dispatcher-authorized, immutable dial decision. ExecuteAuthorized(context.Context, *ExecuteAuthorizedRequest) (*ExecuteAuthorizedResponse, error) ExecuteApproved(context.Context, *ExecuteApprovedRequest) (*ExecuteApprovedResponse, error) + ApplyApprovedTaskControl(context.Context, *ApplyApprovedTaskControlRequest) (*ApplyApprovedTaskControlResponse, error) GetLoadedSIP(context.Context, *GetLoadedSIPRequest) (*GetLoadedSIPResponse, error) GetExecutionPermit(context.Context, *GetExecutionPermitRequest) (*GetExecutionPermitResponse, error) ApplyTaskControl(context.Context, *ApplyTaskControlRequest) (*ApplyTaskControlResponse, error) @@ -303,6 +316,9 @@ func (UnimplementedAgentControlServiceServer) ExecuteAuthorized(context.Context, func (UnimplementedAgentControlServiceServer) ExecuteApproved(context.Context, *ExecuteApprovedRequest) (*ExecuteApprovedResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ExecuteApproved not implemented") } +func (UnimplementedAgentControlServiceServer) ApplyApprovedTaskControl(context.Context, *ApplyApprovedTaskControlRequest) (*ApplyApprovedTaskControlResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ApplyApprovedTaskControl not implemented") +} func (UnimplementedAgentControlServiceServer) GetLoadedSIP(context.Context, *GetLoadedSIPRequest) (*GetLoadedSIPResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetLoadedSIP not implemented") } @@ -480,6 +496,24 @@ func _AgentControlService_ExecuteApproved_Handler(srv interface{}, ctx context.C return interceptor(ctx, in, info, handler) } +func _AgentControlService_ApplyApprovedTaskControl_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApplyApprovedTaskControlRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentControlServiceServer).ApplyApprovedTaskControl(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AgentControlService_ApplyApprovedTaskControl_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentControlServiceServer).ApplyApprovedTaskControl(ctx, req.(*ApplyApprovedTaskControlRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AgentControlService_GetLoadedSIP_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetLoadedSIPRequest) if err := dec(in); err != nil { @@ -695,6 +729,10 @@ var AgentControlService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ExecuteApproved", Handler: _AgentControlService_ExecuteApproved_Handler, }, + { + MethodName: "ApplyApprovedTaskControl", + Handler: _AgentControlService_ApplyApprovedTaskControl_Handler, + }, { MethodName: "GetLoadedSIP", Handler: _AgentControlService_GetLoadedSIP_Handler, diff --git a/internal/dispatcher/approved_control.go b/internal/dispatcher/approved_control.go new file mode 100644 index 0000000..6ebab43 --- /dev/null +++ b/internal/dispatcher/approved_control.go @@ -0,0 +1,65 @@ +package dispatcher + +import ( + "context" + "errors" + "fmt" + "strings" + + agentpb "git.ipao.vip/rogee/go-sip/gen/agent" + "github.com/google/uuid" +) + +var _ CurrentControlAgent = (*ApprovedOriginator)(nil) + +// SendControl dispatches a task-level instruction using the same authenticated +// Agent session as approved execution. Each delivery gets an internal RPC trace +// ID, but no external command ID, idempotency key or revision CAS is invented. +func (o *ApprovedOriginator) SendControl(ctx context.Context, spec CurrentControlSpec) error { + if ctx == nil || o == nil || spec.DispatcherID == "" || spec.DispatcherID != o.DispatcherID || spec.TenantID <= 0 || strings.TrimSpace(spec.TaskID) == "" { + return errors.New("approved Agent task control identity is incomplete") + } + var action agentpb.ControlAction + switch spec.Action { + case "pause": + action = agentpb.ControlAction_CONTROL_ACTION_PAUSE + case "stop": + action = agentpb.ControlAction_CONTROL_ACTION_STOP + case "resume": + action = agentpb.ControlAction_CONTROL_ACTION_RESUME + default: + return errors.New("approved Agent task control action is invalid") + } + var policy agentpb.ActiveCallPolicy + if spec.Action == "resume" { + if spec.ActiveCallPolicy != "" { + return errors.New("approved Agent resume cannot carry an active-call policy") + } + } else { + switch spec.ActiveCallPolicy { + case "hangup": + policy = agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_HANGUP + case "drain": + policy = agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_DRAIN + default: + return errors.New("approved Agent pause/stop requires an active-call policy") + } + } + meta, err := o.activeMeta(ctx) + if err != nil { + return err + } + meta.OperationId = uuid.NewString() + meta.IdempotencyKey = "" + response, err := o.Client.ApplyApprovedTaskControl(ctx, &agentpb.ApplyApprovedTaskControlRequest{ + Meta: meta, DispatcherId: spec.DispatcherID, TenantId: spec.TenantID, + TaskId: spec.TaskID, Action: action, ActiveCallPolicy: policy, + }) + if err != nil { + return fmt.Errorf("Agent task control outcome unknown: %w", err) + } + if response == nil || !response.Accepted { + return errors.New("Agent did not confirm task control application") + } + return nil +} diff --git a/internal/dispatcher/approved_control_test.go b/internal/dispatcher/approved_control_test.go new file mode 100644 index 0000000..c06ee81 --- /dev/null +++ b/internal/dispatcher/approved_control_test.go @@ -0,0 +1,86 @@ +package dispatcher + +import ( + "context" + "strings" + "testing" + + agentpb "git.ipao.vip/rogee/go-sip/gen/agent" + "github.com/google/uuid" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestApprovedAgentControlUsesTaskIdentityAndNoExternalCommandDedup(t *testing.T) { + fake := &fakeApprovedAgentRPC{} + originator, execution := approvedOriginatorFixture(t, fake) + var lastOperation string + for _, tc := range []struct { + action, policy string + wantAction agentpb.ControlAction + wantPolicy agentpb.ActiveCallPolicy + }{ + {"pause", "hangup", agentpb.ControlAction_CONTROL_ACTION_PAUSE, agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_HANGUP}, + {"stop", "drain", agentpb.ControlAction_CONTROL_ACTION_STOP, agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_DRAIN}, + {"resume", "", agentpb.ControlAction_CONTROL_ACTION_RESUME, agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_UNSPECIFIED}, + } { + spec := CurrentControlSpec{DispatcherID: originator.DispatcherID, TenantID: execution.TenantID, TaskID: execution.TaskID, Action: tc.action, ActiveCallPolicy: tc.policy, Reason: "synthetic-private-reason-not-for-agent"} + if err := originator.SendControl(context.Background(), spec); err != nil { + t.Fatalf("current %s control was not applied: %v", tc.action, err) + } + req := fake.controlRequest + if req == nil || req.DispatcherId != spec.DispatcherID || req.TenantId != spec.TenantID || req.TaskId != spec.TaskID || req.Action != tc.wantAction || req.ActiveCallPolicy != tc.wantPolicy { + t.Fatal("Agent received a different task-level control") + } + if req.Meta == nil || req.Meta.IdempotencyKey != "" || uuid.Validate(req.Meta.OperationId) != nil || req.Meta.OperationId == lastOperation { + t.Fatal("control reused an external command ID, idempotency key or RPC trace") + } + if strings.Contains(req.String(), spec.Reason) { + t.Fatal("control leaked the SaaS reason into the Agent request") + } + lastOperation = req.Meta.OperationId + } + if fake.controlCalls != 3 { + t.Fatalf("controls were silently deduplicated: %d", fake.controlCalls) + } +} + +func TestApprovedAgentControlRejectsInvalidInstructionsAndUnknownReply(t *testing.T) { + fake := &fakeApprovedAgentRPC{} + originator, execution := approvedOriginatorFixture(t, fake) + base := CurrentControlSpec{DispatcherID: originator.DispatcherID, TenantID: execution.TenantID, TaskID: execution.TaskID, Action: "pause", ActiveCallPolicy: "hangup"} + for _, tc := range []struct { + name string + edit func(*CurrentControlSpec) + }{ + {"wrong dispatcher", func(spec *CurrentControlSpec) { spec.DispatcherID = "another-dispatcher" }}, + {"tenant zero", func(spec *CurrentControlSpec) { spec.TenantID = 0 }}, + {"task missing", func(spec *CurrentControlSpec) { spec.TaskID = "" }}, + {"unsupported action", func(spec *CurrentControlSpec) { spec.Action = "restart" }}, + {"pause missing policy", func(spec *CurrentControlSpec) { spec.ActiveCallPolicy = "" }}, + {"resume with hangup", func(spec *CurrentControlSpec) { spec.Action = "resume" }}, + } { + t.Run(tc.name, func(t *testing.T) { + spec := base + tc.edit(&spec) + if err := originator.SendControl(context.Background(), spec); err == nil { + t.Fatal("invalid Agent control was dispatched") + } + if fake.controlCalls != 0 { + t.Fatal("invalid Agent control reached RPC") + } + }) + } + fake.controlResponse = &agentpb.ApplyApprovedTaskControlResponse{} + if err := originator.SendControl(context.Background(), base); err == nil { + t.Fatal("unapplied Agent response was treated as completed") + } + fake.controlResponse = nil + fake.controlErr = status.Error(codes.DeadlineExceeded, "synthetic unknown outcome") + if err := originator.SendControl(context.Background(), base); status.Code(err) != codes.DeadlineExceeded { + t.Fatalf("unknown Agent outcome was suppressed: %v", err) + } + if fake.controlCalls != 2 { + t.Fatalf("Agent RPC was retried or silently skipped: %d", fake.controlCalls) + } +} diff --git a/internal/dispatcher/approved_originator.go b/internal/dispatcher/approved_originator.go index bf6b005..2ece692 100644 --- a/internal/dispatcher/approved_originator.go +++ b/internal/dispatcher/approved_originator.go @@ -19,6 +19,7 @@ import ( type ApprovedAgentRPC interface { GetLoadedSIP(context.Context, *agentpb.GetLoadedSIPRequest, ...grpc.CallOption) (*agentpb.GetLoadedSIPResponse, error) ExecuteApproved(context.Context, *agentpb.ExecuteApprovedRequest, ...grpc.CallOption) (*agentpb.ExecuteApprovedResponse, error) + ApplyApprovedTaskControl(context.Context, *agentpb.ApplyApprovedTaskControlRequest, ...grpc.CallOption) (*agentpb.ApplyApprovedTaskControlResponse, error) } // ApprovedOriginator never logs the task or provider bytes: provider JSON diff --git a/internal/dispatcher/approved_originator_test.go b/internal/dispatcher/approved_originator_test.go index 493e9a8..4207e3d 100644 --- a/internal/dispatcher/approved_originator_test.go +++ b/internal/dispatcher/approved_originator_test.go @@ -15,10 +15,14 @@ import ( ) type fakeApprovedAgentRPC struct { - loaded map[string]int64 - loadedErr error - response *agentpb.ExecuteApprovedResponse - request *agentpb.ExecuteApprovedRequest + loaded map[string]int64 + loadedErr error + response *agentpb.ExecuteApprovedResponse + request *agentpb.ExecuteApprovedRequest + controlRequest *agentpb.ApplyApprovedTaskControlRequest + controlResponse *agentpb.ApplyApprovedTaskControlResponse + controlErr error + controlCalls int } func (f *fakeApprovedAgentRPC) ExecuteApproved(_ context.Context, req *agentpb.ExecuteApprovedRequest, _ ...grpc.CallOption) (*agentpb.ExecuteApprovedResponse, error) { @@ -29,6 +33,18 @@ func (f *fakeApprovedAgentRPC) ExecuteApproved(_ context.Context, req *agentpb.E return &agentpb.ExecuteApprovedResponse{Accepted: true, CallId: req.CallId}, nil } +func (f *fakeApprovedAgentRPC) ApplyApprovedTaskControl(_ context.Context, req *agentpb.ApplyApprovedTaskControlRequest, _ ...grpc.CallOption) (*agentpb.ApplyApprovedTaskControlResponse, error) { + f.controlCalls++ + f.controlRequest = req + if f.controlErr != nil { + return nil, f.controlErr + } + if f.controlResponse != nil { + return f.controlResponse, nil + } + return &agentpb.ApplyApprovedTaskControlResponse{Accepted: true}, nil +} + func (f *fakeApprovedAgentRPC) GetLoadedSIP(_ context.Context, _ *agentpb.GetLoadedSIPRequest, _ ...grpc.CallOption) (*agentpb.GetLoadedSIPResponse, error) { if f.loadedErr != nil { return nil, f.loadedErr diff --git a/internal/rpc/approved_control.go b/internal/rpc/approved_control.go new file mode 100644 index 0000000..884648b --- /dev/null +++ b/internal/rpc/approved_control.go @@ -0,0 +1,75 @@ +package rpc + +import ( + "context" + "errors" + "strings" + + agentpb "git.ipao.vip/rogee/go-sip/gen/agent" + "git.ipao.vip/rogee/go-sip/internal/agent" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// ApplyApprovedTaskControl applies a task-scoped control only for the active +// Dispatcher session. It deliberately has no external control command ID or +// revision CAS; repeated deliveries execute the control again. +func (s *Server) ApplyApprovedTaskControl(ctx context.Context, req *agentpb.ApplyApprovedTaskControlRequest) (*agentpb.ApplyApprovedTaskControlResponse, error) { + if s == nil || ctx == nil || req == nil || req.Meta == nil { + return nil, status.Error(codes.InvalidArgument, "approved task control requires a context and session metadata") + } + if err := s.authorize(ctx, req.Meta); err != nil { + return nil, err + } + dispatcherID, err := s.sessions.ApprovedDispatcher(req.Meta, s.now()) + if err != nil { + return nil, err + } + if req.DispatcherId != dispatcherID { + return nil, status.Error(codes.PermissionDenied, "Dispatcher does not own the active Agent session") + } + if s.mode != "mock" { + return nil, status.Error(codes.FailedPrecondition, "approved task control requires isolated Mock mode") + } + if req.TenantId <= 0 || strings.TrimSpace(req.TaskId) == "" { + return nil, status.Error(codes.InvalidArgument, "approved task control identity is incomplete") + } + var action string + switch req.Action { + case agentpb.ControlAction_CONTROL_ACTION_PAUSE: + action = "pause" + case agentpb.ControlAction_CONTROL_ACTION_STOP: + action = "stop" + case agentpb.ControlAction_CONTROL_ACTION_RESUME: + action = "resume" + default: + return nil, status.Error(codes.InvalidArgument, "approved task control action is invalid") + } + var policy string + switch req.ActiveCallPolicy { + case agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_HANGUP: + policy = "hangup" + case agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_DRAIN: + policy = "drain" + case agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_UNSPECIFIED: + default: + return nil, status.Error(codes.InvalidArgument, "approved task control policy is invalid") + } + if (action == "resume" && policy != "") || (action != "resume" && policy == "") { + return nil, status.Error(codes.InvalidArgument, "approved task control policy does not match action") + } + if s.approvedTaskCalls == nil { + return nil, status.Error(codes.FailedPrecondition, "Agent task-control adapter is unavailable") + } + if err := s.approvedTaskCalls.Apply(ctx, agent.TaskIdentity{DispatcherID: dispatcherID, TenantID: req.TenantId, TaskID: req.TaskId}, action, policy); err != nil { + switch { + case errors.Is(err, context.DeadlineExceeded): + return nil, status.Error(codes.DeadlineExceeded, "Agent task control timed out before calls ended") + case errors.Is(err, context.Canceled): + return nil, status.Error(codes.Canceled, "Agent task control interrupted before calls ended") + default: + return nil, status.Error(codes.FailedPrecondition, "Agent task control was not applied") + } + } + return &agentpb.ApplyApprovedTaskControlResponse{Accepted: true}, nil +} diff --git a/internal/rpc/approved_control_test.go b/internal/rpc/approved_control_test.go new file mode 100644 index 0000000..6f6cd26 --- /dev/null +++ b/internal/rpc/approved_control_test.go @@ -0,0 +1,95 @@ +package rpc + +import ( + "context" + "path/filepath" + "testing" + "time" + + agentpb "git.ipao.vip/rogee/go-sip/gen/agent" + "git.ipao.vip/rogee/go-sip/internal/agent" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestApprovedTaskControlRequiresCurrentSessionAndValidTaskPolicy(t *testing.T) { + now := time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC) + execution := approvedTestRequest(t, now) + server := activatedApprovedServer(t, now, filepath.Join(t.TempDir(), "agent-session.json"), execution.DispatcherId, 1, nil) + server.approvedTaskCalls = &agent.TaskCalls{} + request := &agentpb.ApplyApprovedTaskControlRequest{ + Meta: testMeta("control-1", "", 1), DispatcherId: execution.DispatcherId, + TenantId: execution.TenantId, TaskId: execution.TaskId, + Action: agentpb.ControlAction_CONTROL_ACTION_PAUSE, ActiveCallPolicy: agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_HANGUP, + } + response, err := server.ApplyApprovedTaskControl(context.Background(), request) + if err != nil || response == nil || !response.Accepted { + t.Fatalf("authenticated task pause was not applied: response=%v err=%v", response, err) + } + // A second delivery is a second control attempt, not an internal command-ID replay. + if response, err = server.ApplyApprovedTaskControl(context.Background(), request); err != nil || response == nil || !response.Accepted { + t.Fatalf("repeat pause was silently deduplicated or rejected: response=%v err=%v", response, err) + } + request.DispatcherId = "another-dispatcher" + if _, err := server.ApplyApprovedTaskControl(context.Background(), request); status.Code(err) != codes.PermissionDenied { + t.Fatalf("foreign Dispatcher was admitted: %v", err) + } + request.DispatcherId = execution.DispatcherId + request.Meta.SessionGeneration = 2 + if _, err := server.ApplyApprovedTaskControl(context.Background(), request); status.Code(err) != codes.Aborted { + t.Fatalf("stale or unknown session was admitted: %v", err) + } + request.Meta.SessionGeneration = 1 + request.TenantId = 0 + if _, err := server.ApplyApprovedTaskControl(context.Background(), request); status.Code(err) != codes.InvalidArgument { + t.Fatalf("control without a numeric tenant was admitted: %v", err) + } + request.TenantId = execution.TenantId + request.Action = agentpb.ControlAction_CONTROL_ACTION_RESUME + if _, err := server.ApplyApprovedTaskControl(context.Background(), request); status.Code(err) != codes.InvalidArgument { + t.Fatalf("resume with a hangup policy was admitted: %v", err) + } + request.ActiveCallPolicy = agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_UNSPECIFIED + if response, err := server.ApplyApprovedTaskControl(context.Background(), request); err != nil || response == nil || !response.Accepted { + t.Fatalf("approved resume was not applied: response=%v err=%v", response, err) + } + server.approvedTaskCalls = nil + if _, err := server.ApplyApprovedTaskControl(context.Background(), request); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("missing Agent control adapter reported success: %v", err) + } +} + +func TestApprovedTaskStopDrainRetainsBarrierAcrossTimeoutAndRedelivery(t *testing.T) { + now := time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC) + execution := approvedTestRequest(t, now) + server := activatedApprovedServer(t, now, filepath.Join(t.TempDir(), "agent-session.json"), execution.DispatcherId, 1, nil) + calls := &agent.TaskCalls{} + server.approvedTaskCalls = calls + task := agent.TaskIdentity{DispatcherID: execution.DispatcherId, TenantID: execution.TenantId, TaskID: execution.TaskId} + release, err := calls.Register(task, "active-call", func() {}) + if err != nil { + t.Fatal(err) + } + request := &agentpb.ApplyApprovedTaskControlRequest{ + Meta: testMeta("stop", "", 1), DispatcherId: execution.DispatcherId, + TenantId: execution.TenantId, TaskId: execution.TaskId, + Action: agentpb.ControlAction_CONTROL_ACTION_STOP, ActiveCallPolicy: agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_DRAIN, + } + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond) + defer cancel() + if _, err := server.ApplyApprovedTaskControl(ctx, request); status.Code(err) != codes.DeadlineExceeded { + t.Fatalf("stop/drain acknowledged before active call ended: %v", err) + } + request.Action = agentpb.ControlAction_CONTROL_ACTION_RESUME + request.ActiveCallPolicy = agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_UNSPECIFIED + if _, err := server.ApplyApprovedTaskControl(context.Background(), request); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("stopped task resumed after a timed-out drain: %v", err) + } + release() + request.Action = agentpb.ControlAction_CONTROL_ACTION_STOP + request.ActiveCallPolicy = agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_DRAIN + response, err := server.ApplyApprovedTaskControl(context.Background(), request) + if err != nil || response == nil || !response.Accepted { + t.Fatalf("explicit redelivery of stopped task did not drain: response=%v err=%v", response, err) + } +} diff --git a/internal/rpc/server.go b/internal/rpc/server.go index 504de21..a2b6871 100644 --- a/internal/rpc/server.go +++ b/internal/rpc/server.go @@ -13,6 +13,7 @@ import ( "time" agentpb "git.ipao.vip/rogee/go-sip/gen/agent" + "git.ipao.vip/rogee/go-sip/internal/agent" "git.ipao.vip/rogee/go-sip/internal/ai" "git.ipao.vip/rogee/go-sip/internal/calllog" "git.ipao.vip/rogee/go-sip/internal/callwindow" @@ -50,6 +51,8 @@ type ServerOptions struct { LoadedSIP func(context.Context) (map[string]int64, error) // The mock may have issued a call even if its outcome is unknown. MockApprovedOriginate func(context.Context, ApprovedExecution) error + // ApprovedTaskCalls is shared with the approved call runner; nil rejects task controls. + ApprovedTaskCalls *agent.TaskCalls } // Server is the local Unary gRPC state boundary. It owns session/fencing and @@ -76,6 +79,7 @@ type Server struct { mockAuthorizedOriginate func(context.Context, *agentpb.ExecuteAuthorizedRequest) error loadedSIP func(context.Context) (map[string]int64, error) mockApprovedOriginate func(context.Context, ApprovedExecution) error + approvedTaskCalls *agent.TaskCalls sessions *SessionRegistry approvedJournalDir string @@ -178,6 +182,7 @@ func NewServer(options ServerOptions) *Server { mockAuthorizedOriginate: options.MockAuthorizedOriginate, loadedSIP: options.LoadedSIP, mockApprovedOriginate: options.MockApprovedOriginate, + approvedTaskCalls: options.ApprovedTaskCalls, sessions: NewSessionRegistry(options.StatePath), operations: make(map[string]operationRecord), admissions: make(map[string]admissionRecord), diff --git a/proto/ERRORS.md b/proto/ERRORS.md index 325efea..79c0c26 100644 --- a/proto/ERRORS.md +++ b/proto/ERRORS.md @@ -28,9 +28,12 @@ specified state transition and barrier evidence. ## Idempotency keys -`RequestMeta.idempotency_key` is required for mutating methods. The key is -scoped by `(agent_id, operation_id, idempotency_key)` and the durable operation -record also stores the request content digest. Reusing a key with different +For execution and other durably deduplicated mutations, +`RequestMeta.idempotency_key` is scoped by +`(agent_id, operation_id, idempotency_key)` and the durable operation record +also stores the request content digest. The current task-level +`ApplyApprovedTaskControl` is an exception: it may omit the key, has no control +command ID or revision CAS, and processes every delivery. Reusing a key with different content returns `ABORTED`/`RESULT_CODE_CONFLICT`; it never overwrites the first request. @@ -54,6 +57,11 @@ request. - `ApplyTaskControl`: `(execution_id, expected_task_revision, action, idempotency_key)` is CAS-checked. `STOP` is terminal; `PAUSE` may be resumed only by a new authorized request. +- `ApplyApprovedTaskControl`: the active Dispatcher session and numeric + tenant/task identity are checked. It closes local admission before hangup + or drain and succeeds only after registered active calls end. The main + approved-call runner must register those calls before live use. A timeout keeps the + barrier closed; explicit redelivery applies again, with no control dedup. - `ReportExecutionEvent`: `(fact_id, content_sha256)` is the durable fact key. An identical duplicate returns the original receipt; a digest mismatch is a conflict. @@ -81,8 +89,10 @@ request and trace identity: `GetAgentStatus`, `GetBootstrap`, and second business-policy calculation or an implicit permit/fallback. Its mixed/real execution is disabled pending separate authorization. 5. Admission close/drain is a prerequisite barrier. `SetAdmissionState` and - `ApplyTaskControl` are applied only when their expected generation/revision - matches durable state. + the execution-bound `ApplyTaskControl` require their expected + generation/revision. The task-level `ApplyApprovedTaskControl` instead + checks the active Dispatcher session and keeps its local stop irreversible; + Dispatcher durable task state remains authoritative. 6. When the result of a mutation is unknown, the caller first queries the original operation/execution and records `UNKNOWN` if evidence is absent. No new execution ID or new permit is invented for recovery. diff --git a/proto/README.md b/proto/README.md index 18fe5bd..52f9349 100644 --- a/proto/README.md +++ b/proto/README.md @@ -17,6 +17,13 @@ the Agent checks only active session identity and the Dispatcher-issued exclusive deadline. This method is enabled only with an explicit isolated Mock adapter, which sends **no SIP**. Dispatcher V3 mixed/real startup rejects this path; neither the existing `Execute` method nor MQ provides a fallback. +- `ApplyApprovedTaskControl` applies a task-level control for the authenticated +Dispatcher and numeric tenant. Pause/stop first close Agent admission, then +hang up or drain registered active calls before returning success; stop cannot +resume. The approved-call runner must register active calls before this RPC +can protect a live process; that main-entry integration is still pending. +It does not use an execution binding, command ID, revision CAS, or control +message deduplication. The Dispatcher remains the durable task authority. - `accepted` is durable receipt only; `applied`, terminal state and verified asset facts require later evidence. - IDs, epochs, boot/session generations, operation IDs and explicit idempotency diff --git a/proto/agent/agent.proto b/proto/agent/agent.proto index f574076..38bc59d 100644 --- a/proto/agent/agent.proto +++ b/proto/agent/agent.proto @@ -16,6 +16,7 @@ service AgentControlService { // Local P1 Mock: accepts a Dispatcher-authorized, immutable dial decision. rpc ExecuteAuthorized(ExecuteAuthorizedRequest) returns (ExecuteAuthorizedResponse); rpc ExecuteApproved(ExecuteApprovedRequest) returns (ExecuteApprovedResponse); + rpc ApplyApprovedTaskControl(ApplyApprovedTaskControlRequest) returns (ApplyApprovedTaskControlResponse); rpc GetLoadedSIP(GetLoadedSIPRequest) returns (GetLoadedSIPResponse); rpc GetExecutionPermit(GetExecutionPermitRequest) returns (GetExecutionPermitResponse); rpc ApplyTaskControl(ApplyTaskControlRequest) returns (ApplyTaskControlResponse); @@ -442,6 +443,21 @@ message ApplyTaskControlResponse { ExecutionState state = 3; } +// Current task-level control has no external command ID, revision CAS or +// execution binding. The authenticated session must match dispatcher_id. +message ApplyApprovedTaskControlRequest { + RequestMeta meta = 1; + string dispatcher_id = 2; + int64 tenant_id = 3; + string task_id = 4; + ControlAction action = 5; + ActiveCallPolicy active_call_policy = 6; +} + +message ApplyApprovedTaskControlResponse { + bool accepted = 1; +} + message QueryExecutionRequest { RequestMeta meta = 1; ExecutionBinding binding = 2; diff --git a/proto/manifest.json b/proto/manifest.json index 4865690..e0fd30b 100644 --- a/proto/manifest.json +++ b/proto/manifest.json @@ -24,28 +24,28 @@ }, { "path": "proto/ERRORS.md", - "bytes": 5753, - "sha256": "6edd6342ef91c5b04b766e4d82ab003ecb9dc35daab6cf2b6f5b477d7a3ae80d" + "bytes": 6480, + "sha256": "de53827d39324b55563ef05bbdbfde1287c0996a2690c4c030fd7415535d6339" }, { "path": "proto/README.md", - "bytes": 2177, - "sha256": "e6bc250385672025366c14be356deaa26b630ada2f0642370636d8c0afd0b39d" + "bytes": 2711, + "sha256": "ffb72390ff42fb9f99d6586c4d965cfd47c1d1954af1115ac8c5e5d1ba640408" }, { "path": "proto/agent/agent.proto", - "bytes": 14721, - "sha256": "25f888bd3b5097a2d637bf4d1b4c97498102a5f7c67919d41d28e65413a296f7" + "bytes": 15257, + "sha256": "fa8dcfa2066182fce2b1020e637e3e111d1fdcb4bca2cc7e64d702db2394918e" }, { "path": "gen/agent/agent.pb.go", - "bytes": 180766, - "sha256": "1f43d3f7e039f9cfd1fda248e71491eda00f25de6d4a06091a9a3328302b0ccd" + "bytes": 186479, + "sha256": "c0151d146338e470e6ae5bb4a62b646c89e8b096bfeb9caf7d782338cd40b711" }, { "path": "gen/agent/agent_grpc.pb.go", - "bytes": 34240, - "sha256": "4d9ef438fc4a32508ed055bc0cae6f6559b05530835c19851ebf2951680bc08d" + "bytes": 36276, + "sha256": "8c06bac8622c3ee9f34503ed3cf1c408bb368d8687b5164c0e1e9c548273fce5" } ] }