feat: filter receive messages by conversation and query

This commit is contained in:
zhaoyilun
2026-07-10 01:22:17 +08:00
parent bbffa2189d
commit e7324d8aa6
9 changed files with 181 additions and 21 deletions

View File

@@ -26,6 +26,7 @@ Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-repor
- C# `ISphereWinHelper` exists under `native/ISphereWinHelper` and uses the `isphere.helper.v1` stdin/stdout JSON contract. - C# `ISphereWinHelper` exists under `native/ISphereWinHelper` and uses the `isphere.helper.v1` stdin/stdout JSON contract.
- `scripts/verify-win-helper.ps1` and `scripts/verify-go-mcp.ps1` provide repeatable local checks for the helper, eight-tool MCP surface, default empty-source receive/contact/group/file calls, synthetic configured-file receive/contact/group/file smoke, and synthetic configured-directory receive/contact/group/file smoke. - `scripts/verify-win-helper.ps1` and `scripts/verify-go-mcp.ps1` provide repeatable local checks for the helper, eight-tool MCP surface, default empty-source receive/contact/group/file calls, synthetic configured-file receive/contact/group/file smoke, and synthetic configured-directory receive/contact/group/file smoke.
- `isphere_receive_messages` now returns the contract-facing `ok`, `conversation`, `messages`, `next_cursor`, and `audit` envelope while retaining legacy parser-native message fields for compatibility. - `isphere_receive_messages` now returns the contract-facing `ok`, `conversation`, `messages`, `next_cursor`, and `audit` envelope while retaining legacy parser-native message fields for compatibility.
- `isphere_receive_messages` accepts `conversation_id`, `query`, and `limit` for local readonly PacketReader evidence filtering.
- N12-pre and N12R documents define safe offline evidence intake and internal-sandbox live UIA capture procedures. - N12-pre and N12R documents define safe offline evidence intake and internal-sandbox live UIA capture procedures.
- N13/N14/N15 produced selector catalog/report validation infrastructure, but those are supporting validation assets only. - N13/N14/N15 produced selector catalog/report validation infrastructure, but those are supporting validation assets only.
@@ -52,7 +53,7 @@ N13/N14/N15 are pre-business validation results. They can help identify UI eleme
## Current loop ## Current loop
Current loop: `Stage C / Loop C18 - receive-message query/filter contract slice`. Current loop: `Stage C / Loop C19 - receive-message since time filter slice`.
Plan file: `docs/superpowers/plans/2026-07-09-stage-c-log-backed-receive-messages-loop.md`. Plan file: `docs/superpowers/plans/2026-07-09-stage-c-log-backed-receive-messages-loop.md`.
@@ -82,10 +83,11 @@ Current loop output so far:
15. C15: `isphere_send_message` source precheck found no validated write connector; send implementation is blocked pending bridge/API, UIA action, or protocol evidence. 15. C15: `isphere_send_message` source precheck found no validated write connector; send implementation is blocked pending bridge/API, UIA action, or protocol evidence.
16. C16: configured PacketReader source hardening added `ISPHERE_PACKET_LOG_DIR`, deterministic recursive `.log`/`.txt` directory loading, ambiguous file/dir config failure, and configured-directory receive/contact/group/file smoke verification. 16. C16: configured PacketReader source hardening added `ISPHERE_PACKET_LOG_DIR`, deterministic recursive `.log`/`.txt` directory loading, ambiguous file/dir config failure, and configured-directory receive/contact/group/file smoke verification.
17. C17: `isphere_receive_messages` output was aligned to the core read contract envelope and message fields while retaining legacy aliases; verify-go-mcp now asserts contract fields for configured file and directory source smokes. 17. C17: `isphere_receive_messages` output was aligned to the core read contract envelope and message fields while retaining legacy aliases; verify-go-mcp now asserts contract fields for configured file and directory source smokes.
18. C18: `isphere_receive_messages` gained `conversation_id` and `query` filters across source, MCP args, tests, and configured file/directory smoke verification.
## Next business mainline ## Next business mainline
1. Run Stage C Loop C18: add the first safe `isphere_receive_messages` query/filter slice (`conversation_id`, `query`) so digital employees can target configured local-readonly evidence more precisely. 1. Run Stage C Loop C19: add the next safe `isphere_receive_messages` filter (`since`) so digital employees can target recent configured local-readonly evidence by time.
2. Leave `isphere_send_message` blocked until bridge/API, UIA action-chain, or protocol connector evidence is validated. 2. Leave `isphere_send_message` blocked until bridge/API, UIA action-chain, or protocol connector evidence is validated.
3. Leave actual file download/cache mapping as a later connector node until a message-to-cache hash or client download source is validated. 3. Leave actual file download/cache mapping as a later connector node until a message-to-cache hash or client download source is validated.
4. Keep UIA selector/report work as fallback support, not as the primary roadmap. 4. Keep UIA selector/report work as fallback support, not as the primary roadmap.

View File

@@ -184,7 +184,7 @@ Allowed parameters:
- `win_helper_self_check`: zero business parameters. - `win_helper_self_check`: zero business parameters.
- `win_helper_scan_windows`: `include_all_visible` only. - `win_helper_scan_windows`: `include_all_visible` only.
- `win_helper_dump_uia`: `hwnd`, `max_depth`, `include_text`, `max_children` only. - `win_helper_dump_uia`: `hwnd`, `max_depth`, `include_text`, `max_children` only.
- `isphere_receive_messages`: `limit` only. - `isphere_receive_messages`: `conversation_id`, `query`, `limit` only.
- `isphere_search_contacts`: `query`, `limit` only. - `isphere_search_contacts`: `query`, `limit` only.
- `isphere_search_groups`: `query`, `limit` only. - `isphere_search_groups`: `query`, `limit` only.
- `isphere_receive_files`: `conversation_id`, `message_id`, `file_id`, `name_contains`, `mode`, `limit` only. C14 supports `mode` empty or `list`; download is deferred. - `isphere_receive_files`: `conversation_id`, `message_id`, `file_id`, `name_contains`, `mode`, `limit` only. C14 supports `mode` empty or `list`; download is deferred.
@@ -202,7 +202,7 @@ The current runbook verifies eight tools:
- `isphere_search_groups` - `isphere_search_groups`
- `isphere_receive_files` - `isphere_receive_files`
The current log-backed business read tools have parser/source/tool registration and an empty default server source. Raw N12-pre evidence remains under ignored `runs/` paths and is not committed. The current command entry point can read an operator-local encrypted PacketReader log-line file via `ISPHERE_PACKET_LOG_FILE` or a directory of `.log`/`.txt` files via `ISPHERE_PACKET_LOG_DIR`; this is still not a production ingestion claim because raw evidence remains local and uncommitted. `isphere_receive_messages` now exposes contract-facing fields for digital-employee consumption while preserving older aliases for compatibility. `isphere_receive_files` currently supports list mode only; download/cache mapping is deferred. The current log-backed business read tools have parser/source/tool registration and an empty default server source. Raw N12-pre evidence remains under ignored `runs/` paths and is not committed. The current command entry point can read an operator-local encrypted PacketReader log-line file via `ISPHERE_PACKET_LOG_FILE` or a directory of `.log`/`.txt` files via `ISPHERE_PACKET_LOG_DIR`; this is still not a production ingestion claim because raw evidence remains local and uncommitted. `isphere_receive_messages` now exposes contract-facing fields for digital-employee consumption while preserving older aliases for compatibility, and supports `conversation_id` plus keyword `query` filtering. `isphere_receive_files` currently supports list mode only; download/cache mapping is deferred.
Core business tools for contacts, groups, messages, and files are defined in `docs/mcp-core-tools-contract.md`. Send capabilities enter the roadmap through that contract after source discovery, connector selection, preview metadata, execution metadata, and audit records are in place. Core business tools for contacts, groups, messages, and files are defined in `docs/mcp-core-tools-contract.md`. Send capabilities enter the roadmap through that contract after source discovery, connector selection, preview metadata, execution metadata, and audit records are in place.

View File

@@ -17,7 +17,7 @@ Schema notes: `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md`
| MCP tool | Primary source | Fallback source | Evidence file | Decision status | Next implementation slice | | MCP tool | Primary source | Fallback source | Evidence file | Decision status | Next implementation slice |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| `isphere_receive_messages` | decrypted `PacketReader.ProcessPacket` XMPP `<message>` stanzas via `internal/isphere.EncryptedPacketLogSource`; configured by `ISPHERE_PACKET_LOG_FILE` or `ISPHERE_PACKET_LOG_DIR` | decrypted `Smark.SendReceive` transport stanzas; decrypted `SaveToDB` `Chat_OnMessageArrived` traces; wrapped `MsgLib.db` after DB wrapper is solved | `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md#field-mapping-evidence` | C17 response envelope and message fields align to the read contract while keeping legacy aliases; default source remains empty when unset | add `conversation_id` and `query` filters | | `isphere_receive_messages` | decrypted `PacketReader.ProcessPacket` XMPP `<message>` stanzas via `internal/isphere.EncryptedPacketLogSource`; configured by `ISPHERE_PACKET_LOG_FILE` or `ISPHERE_PACKET_LOG_DIR` | decrypted `Smark.SendReceive` transport stanzas; decrypted `SaveToDB` `Chat_OnMessageArrived` traces; wrapped `MsgLib.db` after DB wrapper is solved | `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md#field-mapping-evidence` | C18 supports contract-shaped output plus `conversation_id`, `query`, and `limit` filters; default source remains empty when unset | add `since` time filter |
| `isphere_search_contacts` | bare sender/receiver JIDs extracted from normalized log-backed messages loaded from configured PacketReader file or directory source | decrypted roster/contact stanzas from `Smark.SendReceive`; `MsgLib.db` contact/conversation tables after DB wrapper is solved; UIA helper source if display names are missing | `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md#log-decryption-result` | C16 verification covers default, configured-file, and configured-directory contact smoke; JID-only display/account fallback | enrich display names from roster/db/uia evidence | | `isphere_search_contacts` | bare sender/receiver JIDs extracted from normalized log-backed messages loaded from configured PacketReader file or directory source | decrypted roster/contact stanzas from `Smark.SendReceive`; `MsgLib.db` contact/conversation tables after DB wrapper is solved; UIA helper source if display names are missing | `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md#log-decryption-result` | C16 verification covers default, configured-file, and configured-directory contact smoke; JID-only display/account fallback | enrich display names from roster/db/uia evidence |
| `isphere_search_groups` | decrypted `PacketReader.ProcessPacket` `type="groupchat"` stanzas and conference/MUC JIDs loaded from configured PacketReader file or directory source | `MsgLib.db` group/conversation tables after DB wrapper is solved; UIA helper source if group display names are missing | C9 ignored-log scan: PacketReader 86 groupchat/86 conference hits; Smark 24 groupchat/658 conference/631 muc hits | C16 verification covers default, configured-file, and configured-directory group smoke; JID-only display fallback | enrich group display/member data from roster/db/uia evidence | | `isphere_search_groups` | decrypted `PacketReader.ProcessPacket` `type="groupchat"` stanzas and conference/MUC JIDs loaded from configured PacketReader file or directory source | `MsgLib.db` group/conversation tables after DB wrapper is solved; UIA helper source if group display names are missing | C9 ignored-log scan: PacketReader 86 groupchat/86 conference hits; Smark 24 groupchat/658 conference/631 muc hits | C16 verification covers default, configured-file, and configured-directory group smoke; JID-only display fallback | enrich group display/member data from roster/db/uia evidence |
| `isphere_receive_files` | decrypted `PacketReader.ProcessPacket` file-transfer message stanzas via `internal/isphere.ListFilesFromMessages` and `isphere_receive_files` list mode; configured PacketReader file or directory source; `zyl\importal\<hash>` cache entries remain unlinked | decrypted `Smark.SendReceive` and `SaveToDB` traces for file-reference reconciliation; future UIA/client connector for download | `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md#c12-file-transfer-evidence-precheck` | C16 verification covers default, configured-file, and configured-directory file-list smoke; no log-to-cache/download mapping yet | defer download mapping; align read-tool contract output | | `isphere_receive_files` | decrypted `PacketReader.ProcessPacket` file-transfer message stanzas via `internal/isphere.ListFilesFromMessages` and `isphere_receive_files` list mode; configured PacketReader file or directory source; `zyl\importal\<hash>` cache entries remain unlinked | decrypted `Smark.SendReceive` and `SaveToDB` traces for file-reference reconciliation; future UIA/client connector for download | `docs/source-discovery/2026-07-09-n12-pre-zyl-schema-notes.md#c12-file-transfer-evidence-precheck` | C16 verification covers default, configured-file, and configured-directory file-list smoke; no log-to-cache/download mapping yet | defer download mapping; align read-tool contract output |

View File

@@ -1573,19 +1573,19 @@ Implemented and verified in this loop:
- Preserve current empty-source behavior and current `limit` behavior. - Preserve current empty-source behavior and current `limit` behavior.
- Do not add write/send/file-download behavior. - Do not add write/send/file-download behavior.
- [ ] **Step 1: Write failing source/query test** - [x] **Step 1: Write failing source/query test**
Extend `internal/isphere/source_test.go` with redacted fixtures proving `conversation_id` and keyword filtering. Extend `internal/isphere/source_test.go` with redacted fixtures proving `conversation_id` and keyword filtering.
- [ ] **Step 2: Implement source query filtering** - [x] **Step 2: Implement source query filtering**
Apply filters after decrypt/parse/normalize and before limit truncation, keeping deterministic source order. Apply filters after decrypt/parse/normalize and before limit truncation, keeping deterministic source order.
- [ ] **Step 3: Wire MCP args and verification** - [x] **Step 3: Wire MCP args and verification**
Expose `conversation_id` and `query` on `isphere_receive_messages`, update tool tests and `verify-go-mcp.ps1` synthetic smoke. Expose `conversation_id` and `query` on `isphere_receive_messages`, update tool tests and `verify-go-mcp.ps1` synthetic smoke.
- [ ] **Step 4: Run full verification and commit** - [x] **Step 4: Run full verification and commit**
Run: Run:
@@ -1600,6 +1600,67 @@ Expected: all exit 0. Remove any generated root `isphere-mcp.exe` after build. C
--- ---
## Loop C18 Result
Implemented and verified in this loop:
- `isphere.ReceiveMessagesQuery` now supports `ConversationID` and `Query` in addition to `Limit`.
- `EncryptedPacketLogSource.ReceiveMessages` filters normalized messages by exact conversation id and case-insensitive keyword match over message id, conversation id, sender id, receiver id, text, subject, and receipt id.
- `isphere_receive_messages` MCP args now accept `conversation_id` and `query`, and pass them through to the source.
- `scripts/verify-go-mcp.ps1` now calls configured file and directory source smokes with `conversation_id` plus keyword query arguments.
- Existing empty-source and limit behavior remains unchanged.
---
## Loop C19: Receive-message `since` time filter slice
**Goal:** Add the next safe receive-message filter from the core contract: `since`, using ISO-8601 input from the MCP caller and PacketReader epoch-millisecond timestamps from the normalized local readonly source.
**Planned files:**
- Modify: `internal/isphere/source.go`
- Modify: `internal/isphere/source_test.go`
- Modify: `internal/tools/isphere_read.go`
- Modify: `internal/tools/isphere_read_test.go`
- Modify: `scripts/verify-go-mcp.ps1`
- Modify: `docs/go-mcp-runbook.md`
- Modify: `docs/current-status-card.md`
- Modify: `docs/superpowers/plans/2026-07-09-stage-c-log-backed-receive-messages-loop.md`
**Planned behavior:**
- Add `Since` to `ReceiveMessagesQuery` and `ReceiveMessagesArgs`.
- Accept RFC3339/ISO-8601 input for `since`.
- Compare against message `Timestamp` when it is an epoch-millisecond value.
- Return a clear error for invalid `since` input rather than silently ignoring it.
- Keep `cursor`, `source_preference`, and broader pagination deferred.
- Do not add write/send/file-download behavior.
- [ ] **Step 1: Write failing source `since` test**
Use synthetic PacketReader fixtures before and after an RFC3339 threshold.
- [ ] **Step 2: Implement source `since` filtering**
Parse `since` once per receive call and filter normalized messages by timestamp.
- [ ] **Step 3: Wire MCP args and verification**
Expose `since` on `isphere_receive_messages`, update tool tests and `verify-go-mcp.ps1` synthetic smoke.
- [ ] **Step 4: Run full verification and commit**
Run:
```powershell
git diff --check
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/verify-go-mcp.ps1
```
Expected: all exit 0. Remove any generated root `isphere-mcp.exe` after build. Commit exact C19 paths only and rewrite the next loop from actual results.
---
## Self-Review ## Self-Review
- Spec coverage: the plan follows the user's cyclic requirement: plan first, implement one loop at a time, update the next loop after each result, and ask only on blockers. - Spec coverage: the plan follows the user's cyclic requirement: plan first, implement one loop at a time, update the next loop after each result, and ask only on blockers.

View File

@@ -23,7 +23,9 @@ type Message struct {
} }
type ReceiveMessagesQuery struct { type ReceiveMessagesQuery struct {
Limit int ConversationID string
Query string
Limit int
} }
type ReceiveMessagesResult struct { type ReceiveMessagesResult struct {
@@ -41,9 +43,6 @@ func (s EncryptedPacketLogSource) ReceiveMessages(ctx context.Context, query Rec
} }
messages := make([]Message, 0, limit) messages := make([]Message, 0, limit)
for index, line := range s.Lines { for index, line := range s.Lines {
if len(messages) == limit {
break
}
select { select {
case <-ctx.Done(): case <-ctx.Done():
return ReceiveMessagesResult{}, ctx.Err() return ReceiveMessagesResult{}, ctx.Err()
@@ -57,11 +56,43 @@ func (s EncryptedPacketLogSource) ReceiveMessages(ctx context.Context, query Rec
if err != nil { if err != nil {
return ReceiveMessagesResult{}, fmt.Errorf("parse packet log line %d: %w", index, err) return ReceiveMessagesResult{}, fmt.Errorf("parse packet log line %d: %w", index, err)
} }
messages = append(messages, normalizePacketMessage(parsed)) message := normalizePacketMessage(parsed)
if !receiveMessageMatchesQuery(message, query) {
continue
}
messages = append(messages, message)
if len(messages) == limit {
break
}
} }
return ReceiveMessagesResult{Messages: messages}, nil return ReceiveMessagesResult{Messages: messages}, nil
} }
func receiveMessageMatchesQuery(message Message, query ReceiveMessagesQuery) bool {
if strings.TrimSpace(query.ConversationID) != "" && message.ConversationID != strings.TrimSpace(query.ConversationID) {
return false
}
keyword := strings.ToLower(strings.TrimSpace(query.Query))
if keyword == "" {
return true
}
values := []string{
message.ID,
message.ConversationID,
message.SenderID,
message.ReceiverID,
message.Text,
message.Subject,
message.ReceiptID,
}
for _, value := range values {
if strings.Contains(strings.ToLower(value), keyword) {
return true
}
}
return false
}
func normalizePacketMessage(msg packetlog.Message) Message { func normalizePacketMessage(msg packetlog.Message) Message {
sender := bareJID(msg.From) sender := bareJID(msg.From)
receiver := bareJID(msg.To) receiver := bareJID(msg.To)

View File

@@ -42,6 +42,58 @@ func TestEncryptedPacketLogSourceReturnsNormalizedMessages(t *testing.T) {
} }
} }
func TestEncryptedPacketLogSourceFiltersByConversationAndQuery(t *testing.T) {
first := `--------------------------------------------------------------------------------------------------------------------------------------------
2026/7/7 15:30:07
<message id="msg-alpha" from="sender@imopenfire1-lanzhou/imp_pc_4.1.2.6842" to="receiver@imopenfire1-lanzhou" type="chat">
<body>alpha status update</body>
<received xmlns="urn:xmpp:receipts" id="receipt-alpha" type="1" stamp="" />
<subject>TASK_UPDATE</subject>
<isphere xmlns="isphere.im" type="1001" sendtime="1783423807000" version="1" />
<readed />
</message>`
second := `--------------------------------------------------------------------------------------------------------------------------------------------
2026/7/7 15:31:07
<message id="msg-beta" from="project-room@conference.imopenfire1-lanzhou/imp_pc_4.1.2.6842" to="sender@imopenfire1-lanzhou" type="groupchat">
<body>beta budget redacted-report.docx</body>
<received xmlns="urn:xmpp:receipts" id="receipt-beta" type="1" stamp="" />
<subject>FILE_TRANSFER_CANCEL</subject>
<isphere xmlns="isphere.im" type="1001" sendtime="1783423867000" version="1" />
<readed />
</message>`
source := EncryptedPacketLogSource{Lines: []string{
encryptPacketLineForTest(t, first),
encryptPacketLineForTest(t, second),
}}
got, err := source.ReceiveMessages(context.Background(), ReceiveMessagesQuery{
ConversationID: "project-room@conference.imopenfire1-lanzhou|sender@imopenfire1-lanzhou",
Query: "BUDGET",
Limit: 10,
})
if err != nil {
t.Fatalf("ReceiveMessages returned error: %v", err)
}
if len(got.Messages) != 1 {
t.Fatalf("message count = %d, want 1: %+v", len(got.Messages), got.Messages)
}
if got.Messages[0].ID != "msg-beta" {
t.Fatalf("message id = %q, want msg-beta", got.Messages[0].ID)
}
empty, err := source.ReceiveMessages(context.Background(), ReceiveMessagesQuery{
ConversationID: "project-room@conference.imopenfire1-lanzhou|sender@imopenfire1-lanzhou",
Query: "alpha",
Limit: 10,
})
if err != nil {
t.Fatalf("ReceiveMessages returned error for empty query: %v", err)
}
if len(empty.Messages) != 0 {
t.Fatalf("empty query returned %+v, want none", empty.Messages)
}
}
func encryptPacketLineForTest(t *testing.T, plaintext string) string { func encryptPacketLineForTest(t *testing.T, plaintext string) string {
t.Helper() t.Helper()
block, err := des.NewCipher([]byte("hyhccdtm")) block, err := des.NewCipher([]byte("hyhccdtm"))

View File

@@ -18,7 +18,9 @@ type ReceiveMessagesSource interface {
} }
type ReceiveMessagesArgs struct { type ReceiveMessagesArgs struct {
Limit int `json:"limit,omitempty" jsonschema:"maximum number of messages to return; zero or negative returns all available messages"` ConversationID string `json:"conversation_id,omitempty" jsonschema:"exact conversation id filter for local readonly message logs"`
Query string `json:"query,omitempty" jsonschema:"case-insensitive keyword filter over message text, subject, ids, and participants"`
Limit int `json:"limit,omitempty" jsonschema:"maximum number of messages to return; zero or negative returns all available messages"`
} }
func RegisterISphereReadTools(server *mcp.Server, source ReceiveMessagesSource) { func RegisterISphereReadTools(server *mcp.Server, source ReceiveMessagesSource) {
@@ -31,7 +33,11 @@ func RegisterISphereReadTools(server *mcp.Server, source ReceiveMessagesSource)
Description: "Return iSphere messages from the configured read-only log-backed source.", Description: "Return iSphere messages from the configured read-only log-backed source.",
}, func(ctx context.Context, _ *mcp.CallToolRequest, input ReceiveMessagesArgs) (*mcp.CallToolResult, map[string]any, error) { }, func(ctx context.Context, _ *mcp.CallToolRequest, input ReceiveMessagesArgs) (*mcp.CallToolResult, map[string]any, error) {
started := time.Now().UTC() started := time.Now().UTC()
result, err := source.ReceiveMessages(ctx, isphere.ReceiveMessagesQuery{Limit: input.Limit}) result, err := source.ReceiveMessages(ctx, isphere.ReceiveMessagesQuery{
ConversationID: input.ConversationID,
Query: input.Query,
Limit: input.Limit,
})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -42,7 +42,7 @@ func TestISphereReceiveMessagesToolReturnsSourceMessages(t *testing.T) {
callResult, err := session.CallTool(context.Background(), &mcp.CallToolParams{ callResult, err := session.CallTool(context.Background(), &mcp.CallToolParams{
Name: ToolNameReceiveMessages, Name: ToolNameReceiveMessages,
Arguments: map[string]any{"limit": 5}, Arguments: map[string]any{"conversation_id": "sender@imopenfire1-lanzhou|receiver@imopenfire1-lanzhou", "query": "REPORT", "limit": 5},
}) })
if err != nil { if err != nil {
t.Fatalf("call %s: %v", ToolNameReceiveMessages, err) t.Fatalf("call %s: %v", ToolNameReceiveMessages, err)
@@ -50,8 +50,8 @@ func TestISphereReceiveMessagesToolReturnsSourceMessages(t *testing.T) {
if callResult.IsError { if callResult.IsError {
t.Fatalf("call result is error: %+v", callResult) t.Fatalf("call result is error: %+v", callResult)
} }
if len(fake.queries) != 1 || fake.queries[0].Limit != 5 { if len(fake.queries) != 1 || fake.queries[0].Limit != 5 || fake.queries[0].ConversationID != "sender@imopenfire1-lanzhou|receiver@imopenfire1-lanzhou" || fake.queries[0].Query != "REPORT" {
t.Fatalf("queries = %+v, want one limit=5", fake.queries) t.Fatalf("queries = %+v, want conversation_id/query/limit", fake.queries)
} }
var decoded struct { var decoded struct {

View File

@@ -298,7 +298,11 @@ func verifyConfiguredReceiveSource(ctx context.Context) (int, int, int, int) {
} }
}() }()
callResult, err := session.CallTool(serverCtx, &mcp.CallToolParams{Name: "isphere_receive_messages", Arguments: map[string]any{"limit": 5}}) callResult, err := session.CallTool(serverCtx, &mcp.CallToolParams{Name: "isphere_receive_messages", Arguments: map[string]any{
"conversation_id": "project-room@conference.imopenfire1-lanzhou|sender@imopenfire1-lanzhou",
"query": "report",
"limit": 5,
}})
if err != nil { if err != nil {
fail("fixture/call isphere_receive_messages", err) fail("fixture/call isphere_receive_messages", err)
} }
@@ -418,7 +422,11 @@ func verifyConfiguredDirectorySource(ctx context.Context) (int, int, int, int) {
} }
}() }()
callResult, err := session.CallTool(serverCtx, &mcp.CallToolParams{Name: "isphere_receive_messages", Arguments: map[string]any{"limit": 5}}) callResult, err := session.CallTool(serverCtx, &mcp.CallToolParams{Name: "isphere_receive_messages", Arguments: map[string]any{
"conversation_id": "project-room@conference.imopenfire1-lanzhou|sender@imopenfire1-lanzhou",
"query": "dir-report",
"limit": 5,
}})
if err != nil { if err != nil {
fail("dir_fixture/call isphere_receive_messages", err) fail("dir_fixture/call isphere_receive_messages", err)
} }