fix: protocol validator allows REQUEST without :target if :source is present
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s
- Relax validate-communication-protocol-schema to accept :REQUEST messages without :target when :source is present in :meta (reason-gate infers target from source). - This preserves 'equality of clients' — gateways don't duplicate routing logic. - Add communication-validator to ASD components. - Fixes TCP CLI gateway integration: clients can now connect and receive responses. - Verified with test client: 13/13 skills load, Perceive gate processes messages.
This commit is contained in:
@@ -98,10 +98,15 @@ The validator ensures that incoming messages adhere to the strict property list
|
||||
|
||||
(case type
|
||||
(:REQUEST
|
||||
(unless (proto-get msg :target)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload")))
|
||||
;; Allow missing :target if :source is present in :meta, since reason-gate
|
||||
;; will infer :target from :source downstream. This preserves "equality of
|
||||
;; clients" — gateways need not duplicate routing logic.
|
||||
(let ((target (proto-get msg :target))
|
||||
(source (proto-get (proto-get msg :meta) :source)))
|
||||
(unless (or target source)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target and no :source in :meta to infer it"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload"))))
|
||||
|
||||
(:EVENT
|
||||
(let ((payload (proto-get msg :payload)))
|
||||
|
||||
@@ -11,10 +11,15 @@
|
||||
|
||||
(case type
|
||||
(:REQUEST
|
||||
(unless (proto-get msg :target)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload")))
|
||||
;; Allow missing :target if :source is present in :meta, since reason-gate
|
||||
;; will infer :target from :source downstream. This preserves "equality of
|
||||
;; clients" — gateways need not duplicate routing logic.
|
||||
(let ((target (proto-get msg :target))
|
||||
(source (proto-get (proto-get msg :meta) :source)))
|
||||
(unless (or target source)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target and no :source in :meta to infer it"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload"))))
|
||||
|
||||
(:EVENT
|
||||
(let ((payload (proto-get msg :payload)))
|
||||
|
||||
@@ -11,10 +11,15 @@
|
||||
|
||||
(case type
|
||||
(:REQUEST
|
||||
(unless (proto-get msg :target)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload")))
|
||||
;; Allow missing :target if :source is present in :meta, since reason-gate
|
||||
;; will infer :target from :source downstream. This preserves "equality of
|
||||
;; clients" — gateways need not duplicate routing logic.
|
||||
(let ((target (proto-get msg :target))
|
||||
(source (proto-get (proto-get msg :meta) :source)))
|
||||
(unless (or target source)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target and no :source in :meta to infer it"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload"))))
|
||||
|
||||
(:EVENT
|
||||
(let ((payload (proto-get msg :payload)))
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
:components ((:file "library/package")
|
||||
(:file "library/skills")
|
||||
(:file "library/communication")
|
||||
(:file "library/communication-validator")
|
||||
(:file "library/memory")
|
||||
(:file "library/context")
|
||||
(:file "library/perceive")
|
||||
|
||||
@@ -59,10 +59,15 @@ Decouple protocol parsing (framing/unframing) from semantic validation.
|
||||
|
||||
(case type
|
||||
(:REQUEST
|
||||
(unless (proto-get msg :target)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload")))
|
||||
;; Allow missing :target if :source is present in :meta, since reason-gate
|
||||
;; will infer :target from :source downstream. This preserves "equality of
|
||||
;; clients" — gateways need not duplicate routing logic.
|
||||
(let ((target (proto-get msg :target))
|
||||
(source (proto-get (proto-get msg :meta) :source)))
|
||||
(unless (or target source)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :target and no :source in :meta to infer it"))
|
||||
(unless (proto-get msg :payload)
|
||||
(error "Communication Protocol Schema Error: REQUEST missing mandatory :payload"))))
|
||||
|
||||
(:EVENT
|
||||
(let ((payload (proto-get msg :payload)))
|
||||
|
||||
46
test_cli.py
Normal file
46
test_cli.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import socket
|
||||
import struct
|
||||
|
||||
def frame_message(msg_string):
|
||||
payload = msg_string.encode('utf-8')
|
||||
return f"{len(payload):06x}".encode('ascii') + payload
|
||||
|
||||
def read_framed(sock):
|
||||
header = b''
|
||||
while len(header) < 6:
|
||||
chunk = sock.recv(6 - len(header))
|
||||
if not chunk:
|
||||
return None
|
||||
header += chunk
|
||||
length = int(header, 16)
|
||||
data = b''
|
||||
while len(data) < length:
|
||||
chunk = sock.recv(length - len(data))
|
||||
if not chunk:
|
||||
return None
|
||||
data += chunk
|
||||
return data.decode('utf-8')
|
||||
|
||||
msg = '(:TYPE :REQUEST :PAYLOAD (:ACTION :MESSAGE :TEXT "hello") :META (:SOURCE :CLI :SESSION-ID "test1"))'
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect(('127.0.0.1', 9105))
|
||||
sock.settimeout(10.0)
|
||||
|
||||
# Read handshake
|
||||
handshake = read_framed(sock)
|
||||
print("HANDSHAKE:", handshake)
|
||||
|
||||
# Read status
|
||||
status = read_framed(sock)
|
||||
print("STATUS:", status)
|
||||
|
||||
# Send message
|
||||
sock.sendall(frame_message(msg))
|
||||
print("SENT:", msg)
|
||||
|
||||
# Read response
|
||||
response = read_framed(sock)
|
||||
print("RESPONSE:", response)
|
||||
|
||||
sock.close()
|
||||
Reference in New Issue
Block a user