kimi-agent-module-api 2.2.0__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {kimi_agent_module_api-2.2.0/src/kimi_agent_module_api.egg-info → kimi_agent_module_api-2.3.0}/PKG-INFO +11 -7
  2. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/README.md +10 -6
  3. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/pyproject.toml +1 -1
  4. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/__init__.py +4 -0
  5. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/tools.py +36 -2
  6. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0/src/kimi_agent_module_api.egg-info}/PKG-INFO +11 -7
  7. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/tests/test_contracts.py +62 -3
  8. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/LICENSE +0 -0
  9. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/setup.cfg +0 -0
  10. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/contracts.py +0 -0
  11. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/events.py +0 -0
  12. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/files.py +0 -0
  13. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/images.py +0 -0
  14. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/py.typed +0 -0
  15. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/settings.py +0 -0
  16. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/testing.py +0 -0
  17. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api/trust.py +0 -0
  18. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api.egg-info/SOURCES.txt +0 -0
  19. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api.egg-info/dependency_links.txt +0 -0
  20. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api.egg-info/requires.txt +0 -0
  21. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/src/kimi_agent_module_api.egg-info/top_level.txt +0 -0
  22. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/tests/test_files.py +0 -0
  23. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/tests/test_public_api.py +0 -0
  24. {kimi_agent_module_api-2.2.0 → kimi_agent_module_api-2.3.0}/tests/test_testing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kimi-agent-module-api
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Stable contracts for community-built assistant modules
5
5
  Author: Webhead
6
6
  License-Expression: MIT
@@ -84,11 +84,13 @@ Message-deletion events include cached author classification:
84
84
  `MessageDeleteEvent.author_is_bot` and `MessageBulkDeleteEvent.bot_message_ids`.
85
85
  The values remain unknown for messages that were absent from Discord's cache.
86
86
 
87
- SDK 2.1 adds `ModuleToolContext.trigger_discord_message_id`. Mention-path tool
88
- calls receive the exact source Discord message snowflake; other surfaces receive
89
- `None`. Modules that act on a user's source message should require
90
- `kimi-agent-module-api>=2.1,<3`, reject `None`, fetch that exact message through
91
- `ctx.discord`, and verify its author before acting.
87
+ SDK 2.1 adds `ModuleToolContext.trigger_discord_message_id`. SDK 2.3 adds
88
+ `trigger_discord_message_snapshot`, an immutable host-owned capture of the
89
+ message, guild, channel, author, content, and bot status made at turn entry.
90
+ Mention-path tool calls receive both; personal and non-message surfaces receive
91
+ `None`. Modules that need authoritative evidence from the triggering message
92
+ should require `kimi-agent-module-api>=2.3,<3` and use the snapshot instead of
93
+ re-fetching mutable or deletable Discord state.
92
94
 
93
95
  Modules use namespaced guild documents and the physical table names returned
94
96
  by `ctx.storage.table()`.
@@ -101,7 +103,9 @@ keep `api_version=2` and receive `files=None` without the permission.
101
103
  `read_attachment(id, max_bytes=...)` and `read_workspace(path, max_bytes=...)`
102
104
  return bounded bytes without network downloads. The reader expires when the handler
103
105
  returns and is scoped to the actual caller. `testing.FakeToolFiles` supports
104
- independent tests. See the
106
+ independent tests. Module `ctx.http` methods apply an 8 MiB host ceiling even when
107
+ callers supply `max_bytes`; `download` buffers and validates the bounded response
108
+ before yielding chunks so connections are released on early consumer exit. See the
105
109
  [file access guide](https://github.com/webhead2oo9/kimi-agent/blob/main/docs/module-files.md)
106
110
  for moderation, reply-image availability, privacy, and limits.
107
111
 
@@ -67,11 +67,13 @@ Message-deletion events include cached author classification:
67
67
  `MessageDeleteEvent.author_is_bot` and `MessageBulkDeleteEvent.bot_message_ids`.
68
68
  The values remain unknown for messages that were absent from Discord's cache.
69
69
 
70
- SDK 2.1 adds `ModuleToolContext.trigger_discord_message_id`. Mention-path tool
71
- calls receive the exact source Discord message snowflake; other surfaces receive
72
- `None`. Modules that act on a user's source message should require
73
- `kimi-agent-module-api>=2.1,<3`, reject `None`, fetch that exact message through
74
- `ctx.discord`, and verify its author before acting.
70
+ SDK 2.1 adds `ModuleToolContext.trigger_discord_message_id`. SDK 2.3 adds
71
+ `trigger_discord_message_snapshot`, an immutable host-owned capture of the
72
+ message, guild, channel, author, content, and bot status made at turn entry.
73
+ Mention-path tool calls receive both; personal and non-message surfaces receive
74
+ `None`. Modules that need authoritative evidence from the triggering message
75
+ should require `kimi-agent-module-api>=2.3,<3` and use the snapshot instead of
76
+ re-fetching mutable or deletable Discord state.
75
77
 
76
78
  Modules use namespaced guild documents and the physical table names returned
77
79
  by `ctx.storage.table()`.
@@ -84,7 +86,9 @@ keep `api_version=2` and receive `files=None` without the permission.
84
86
  `read_attachment(id, max_bytes=...)` and `read_workspace(path, max_bytes=...)`
85
87
  return bounded bytes without network downloads. The reader expires when the handler
86
88
  returns and is scoped to the actual caller. `testing.FakeToolFiles` supports
87
- independent tests. See the
89
+ independent tests. Module `ctx.http` methods apply an 8 MiB host ceiling even when
90
+ callers supply `max_bytes`; `download` buffers and validates the bounded response
91
+ before yielding chunks so connections are released on early consumer exit. See the
88
92
  [file access guide](https://github.com/webhead2oo9/kimi-agent/blob/main/docs/module-files.md)
89
93
  for moderation, reply-image availability, privacy, and limits.
90
94
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kimi-agent-module-api"
3
- version = "2.2.0"
3
+ version = "2.3.0"
4
4
  description = "Stable contracts for community-built assistant modules"
5
5
  requires-python = ">=3.14"
6
6
  authors = [{ name = "Webhead" }]
@@ -42,6 +42,8 @@ from kimi_agent_module_api.tools import (
42
42
  ModuleToolContext,
43
43
  ModuleToolHandler,
44
44
  ModuleToolRegistry,
45
+ ModuleTurnBudget,
46
+ TriggeringDiscordMessageSnapshot,
45
47
  )
46
48
  from kimi_agent_module_api.trust import TrustTier
47
49
 
@@ -173,6 +175,7 @@ __all__ = [
173
175
  "ModuleToolContext",
174
176
  "ModuleToolHandler",
175
177
  "ModuleToolRegistry",
178
+ "ModuleTurnBudget",
176
179
  "OutgoingLayout",
177
180
  "ProposalActor",
178
181
  "ProposalError",
@@ -188,6 +191,7 @@ __all__ = [
188
191
  "ToolAttachment",
189
192
  "ToolFile",
190
193
  "ToolFiles",
194
+ "TriggeringDiscordMessageSnapshot",
191
195
  "TrustTier",
192
196
  "render_guild_settings",
193
197
  ]
@@ -6,8 +6,29 @@ from collections.abc import Callable, Coroutine, Mapping
6
6
  from dataclasses import dataclass, field
7
7
  from typing import Any, Protocol
8
8
 
9
- from kimi_agent_module_api.trust import TrustTier
10
9
  from kimi_agent_module_api.files import ToolFiles
10
+ from kimi_agent_module_api.trust import TrustTier
11
+
12
+
13
+ class ModuleTurnBudget(Protocol):
14
+ """Host-owned counters shared by every module call in one outer model turn."""
15
+
16
+ def consume(self, name: str, limit: int) -> bool:
17
+ """Consume one named allowance, or return ``False`` without changing it."""
18
+
19
+ ...
20
+
21
+
22
+ @dataclass(frozen=True, slots=True)
23
+ class TriggeringDiscordMessageSnapshot:
24
+ """Immutable evidence captured from the Discord message at turn entry."""
25
+
26
+ message_id: int
27
+ guild_id: int
28
+ channel_id: int
29
+ author_id: int
30
+ content: str
31
+ author_is_bot: bool
11
32
 
12
33
 
13
34
  @dataclass(frozen=True, slots=True)
@@ -36,6 +57,13 @@ class ModuleToolContext:
36
57
  # Invocation-scoped read-only port. Declare permissions.tool_files and
37
58
  # require tools.files.v1; never retain this port beyond the handler.
38
59
  files: ToolFiles | None = None
60
+ # Host-owned values captured before turn preparation can await. Unlike a
61
+ # later Discord fetch, this evidence cannot change or disappear mid-turn.
62
+ # Added after all API 2.2 fields to preserve positional construction.
63
+ trigger_discord_message_snapshot: TriggeringDiscordMessageSnapshot | None = None
64
+ # Mutable host-owned port whose lifetime is the complete outer model turn.
65
+ # Counters are automatically namespaced to the installed module.
66
+ turn_budget: ModuleTurnBudget | None = None
39
67
 
40
68
 
41
69
  type ModuleToolHandler = Callable[[dict[str, Any], ModuleToolContext], Coroutine[Any, Any, str]]
@@ -71,4 +99,10 @@ class ModuleToolRegistry(Protocol):
71
99
  ) -> None: ...
72
100
 
73
101
 
74
- __all__ = ["ModuleToolContext", "ModuleToolHandler", "ModuleToolRegistry"]
102
+ __all__ = [
103
+ "ModuleToolContext",
104
+ "ModuleToolHandler",
105
+ "ModuleToolRegistry",
106
+ "ModuleTurnBudget",
107
+ "TriggeringDiscordMessageSnapshot",
108
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kimi-agent-module-api
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Stable contracts for community-built assistant modules
5
5
  Author: Webhead
6
6
  License-Expression: MIT
@@ -84,11 +84,13 @@ Message-deletion events include cached author classification:
84
84
  `MessageDeleteEvent.author_is_bot` and `MessageBulkDeleteEvent.bot_message_ids`.
85
85
  The values remain unknown for messages that were absent from Discord's cache.
86
86
 
87
- SDK 2.1 adds `ModuleToolContext.trigger_discord_message_id`. Mention-path tool
88
- calls receive the exact source Discord message snowflake; other surfaces receive
89
- `None`. Modules that act on a user's source message should require
90
- `kimi-agent-module-api>=2.1,<3`, reject `None`, fetch that exact message through
91
- `ctx.discord`, and verify its author before acting.
87
+ SDK 2.1 adds `ModuleToolContext.trigger_discord_message_id`. SDK 2.3 adds
88
+ `trigger_discord_message_snapshot`, an immutable host-owned capture of the
89
+ message, guild, channel, author, content, and bot status made at turn entry.
90
+ Mention-path tool calls receive both; personal and non-message surfaces receive
91
+ `None`. Modules that need authoritative evidence from the triggering message
92
+ should require `kimi-agent-module-api>=2.3,<3` and use the snapshot instead of
93
+ re-fetching mutable or deletable Discord state.
92
94
 
93
95
  Modules use namespaced guild documents and the physical table names returned
94
96
  by `ctx.storage.table()`.
@@ -101,7 +103,9 @@ keep `api_version=2` and receive `files=None` without the permission.
101
103
  `read_attachment(id, max_bytes=...)` and `read_workspace(path, max_bytes=...)`
102
104
  return bounded bytes without network downloads. The reader expires when the handler
103
105
  returns and is scoped to the actual caller. `testing.FakeToolFiles` supports
104
- independent tests. See the
106
+ independent tests. Module `ctx.http` methods apply an 8 MiB host ceiling even when
107
+ callers supply `max_bytes`; `download` buffers and validates the bounded response
108
+ before yielding chunks so connections are released on early consumer exit. See the
105
109
  [file access guide](https://github.com/webhead2oo9/kimi-agent/blob/main/docs/module-files.md)
106
110
  for moderation, reply-image availability, privacy, and limits.
107
111
 
@@ -2,8 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from importlib.metadata import version
6
5
  import dataclasses
6
+ from importlib.metadata import version
7
7
  from typing import Any
8
8
 
9
9
  import pytest
@@ -19,6 +19,7 @@ from kimi_agent_module_api import (
19
19
  ModuleRuntimeContext,
20
20
  ModuleSpec,
21
21
  ModuleToolContext,
22
+ TriggeringDiscordMessageSnapshot,
22
23
  TrustTier,
23
24
  render_guild_settings,
24
25
  )
@@ -83,8 +84,66 @@ def test_spec_and_runtime_context_keep_stable_defaults() -> None:
83
84
  assert {"events", "scheduler", "storage", "discord", "interactions", "services"} <= required
84
85
 
85
86
 
86
- def test_distribution_version_includes_tool_files_contract() -> None:
87
- assert version("kimi-agent-module-api") == "2.2.0"
87
+ def test_distribution_version_includes_triggering_message_snapshot_contract() -> None:
88
+ assert version("kimi-agent-module-api") == "2.3.0"
89
+
90
+
91
+ def test_triggering_discord_message_snapshot_is_immutable() -> None:
92
+ snapshot = TriggeringDiscordMessageSnapshot(
93
+ message_id=11,
94
+ guild_id=22,
95
+ channel_id=33,
96
+ author_id=44,
97
+ content="original",
98
+ author_is_bot=False,
99
+ )
100
+
101
+ with pytest.raises(dataclasses.FrozenInstanceError):
102
+ snapshot.content = "edited" # type: ignore[misc]
103
+
104
+
105
+ def test_module_tool_context_preserves_api_2_2_nine_positional_arguments() -> None:
106
+ files = object()
107
+
108
+ context = ModuleToolContext(
109
+ 11,
110
+ "Alice",
111
+ 22,
112
+ 33,
113
+ 44,
114
+ TrustTier.REGULAR,
115
+ {"demo": {"enabled": True}},
116
+ 55,
117
+ files, # type: ignore[arg-type]
118
+ )
119
+
120
+ assert context.files is files
121
+ assert context.trigger_discord_message_snapshot is None
122
+
123
+
124
+ def test_module_tool_context_adds_turn_budget_after_prior_positional_fields() -> None:
125
+ class Budget:
126
+ def consume(self, name: str, limit: int) -> bool:
127
+ return bool(name) and limit > 0
128
+
129
+ snapshot = TriggeringDiscordMessageSnapshot(55, 22, 33, 11, "content", False)
130
+ budget = Budget()
131
+ context = ModuleToolContext(
132
+ 11,
133
+ "Alice",
134
+ 22,
135
+ 33,
136
+ 44,
137
+ TrustTier.REGULAR,
138
+ {},
139
+ 55,
140
+ None,
141
+ snapshot,
142
+ budget,
143
+ )
144
+
145
+ assert context.trigger_discord_message_snapshot is snapshot
146
+ assert context.turn_budget is budget
88
147
 
89
148
 
90
149
  def test_spec_requires_an_explicit_keyword_api_version() -> None: