nextloop 0.1.0rc1__tar.gz → 0.1.0rc2__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 (35) hide show
  1. {nextloop-0.1.0rc1/src/nextloop.egg-info → nextloop-0.1.0rc2}/PKG-INFO +5 -4
  2. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/README.md +4 -3
  3. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/pyproject.toml +1 -1
  4. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/adapters/memory.py +6 -1
  5. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/adapters/sqlite.py +1 -1
  6. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/events/project.py +18 -1
  7. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2/src/nextloop.egg-info}/PKG-INFO +5 -4
  8. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/tests/test_loop.py +3 -0
  9. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/LICENSE +0 -0
  10. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/setup.cfg +0 -0
  11. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/__init__.py +0 -0
  12. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/adapters/__init__.py +0 -0
  13. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/adapters/_sse.py +0 -0
  14. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/adapters/anthropic.py +0 -0
  15. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/adapters/openai.py +0 -0
  16. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/contracts.py +0 -0
  17. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/driver.py +0 -0
  18. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/events/__init__.py +0 -0
  19. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/events/outcome.py +0 -0
  20. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/events/repair.py +0 -0
  21. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/events/response.py +0 -0
  22. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/execute/__init__.py +0 -0
  23. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/execute/batch.py +0 -0
  24. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/execute/model.py +0 -0
  25. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/execute/tools.py +0 -0
  26. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/loop.py +0 -0
  27. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop/py.typed +0 -0
  28. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop.egg-info/SOURCES.txt +0 -0
  29. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop.egg-info/dependency_links.txt +0 -0
  30. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop.egg-info/requires.txt +0 -0
  31. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/src/nextloop.egg-info/top_level.txt +0 -0
  32. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/tests/test_events.py +0 -0
  33. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/tests/test_failures.py +0 -0
  34. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/tests/test_providers.py +0 -0
  35. {nextloop-0.1.0rc1 → nextloop-0.1.0rc2}/tests/test_stores.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextloop
3
- Version: 0.1.0rc1
3
+ Version: 0.1.0rc2
4
4
  Summary: An embeddable AgentLoop with explicit event, tool, recovery, and delivery semantics
5
5
  Author-email: 12bitsD <bis12@163.com>
6
6
  License-Expression: MIT
@@ -30,12 +30,12 @@ Dynamic: license-file
30
30
 
31
31
  A small, embeddable Python AgentLoop with explicit execution, recovery, and delivery semantics.
32
32
 
33
- Current version: **0.1.0rc1**.
33
+ Current version: **0.1.0rc2**.
34
34
 
35
35
  ## Install
36
36
 
37
37
  ```bash
38
- python -m pip install nextloop==0.1.0rc1
38
+ python -m pip install nextloop==0.1.0rc2
39
39
  ```
40
40
 
41
41
  For local development:
@@ -123,11 +123,12 @@ The release-candidate checks cover:
123
123
  - resource-lock recovery, conflict prevention, and explicit release;
124
124
  - real subprocess exits during Tool execution and final delivery, followed by SQLite recovery;
125
125
  - recorded OpenAI and Anthropic SSE streams;
126
+ - 12 live Kimi scenarios across both protocols, real Tool usage, parallel execution, recovery, steer, cancellation, Compaction, and WorkingContext;
126
127
  - `ruff`, `mypy`, wheel/sdist builds, `twine check`, and clean wheel installation.
127
128
 
128
129
  Current limits:
129
130
 
130
- - Hosted-model smoke and nika integration are separate acceptance work.
131
+ - nika integration is separate acceptance work.
131
132
  - Concurrent writers across multiple processes fail closed; they are not coordinated.
132
133
  - Large-asset lifecycle, backup, and GC are not part of this release candidate.
133
134
 
@@ -2,12 +2,12 @@
2
2
 
3
3
  A small, embeddable Python AgentLoop with explicit execution, recovery, and delivery semantics.
4
4
 
5
- Current version: **0.1.0rc1**.
5
+ Current version: **0.1.0rc2**.
6
6
 
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- python -m pip install nextloop==0.1.0rc1
10
+ python -m pip install nextloop==0.1.0rc2
11
11
  ```
12
12
 
13
13
  For local development:
@@ -95,11 +95,12 @@ The release-candidate checks cover:
95
95
  - resource-lock recovery, conflict prevention, and explicit release;
96
96
  - real subprocess exits during Tool execution and final delivery, followed by SQLite recovery;
97
97
  - recorded OpenAI and Anthropic SSE streams;
98
+ - 12 live Kimi scenarios across both protocols, real Tool usage, parallel execution, recovery, steer, cancellation, Compaction, and WorkingContext;
98
99
  - `ruff`, `mypy`, wheel/sdist builds, `twine check`, and clean wheel installation.
99
100
 
100
101
  Current limits:
101
102
 
102
- - Hosted-model smoke and nika integration are separate acceptance work.
103
+ - nika integration is separate acceptance work.
103
104
  - Concurrent writers across multiple processes fail closed; they are not coordinated.
104
105
  - Large-asset lifecycle, backup, and GC are not part of this release candidate.
105
106
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "nextloop"
7
- version = "0.1.0rc1"
7
+ version = "0.1.0rc2"
8
8
  description = "An embeddable AgentLoop with explicit event, tool, recovery, and delivery semantics"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -7,6 +7,7 @@ from collections.abc import Sequence
7
7
 
8
8
  from ..contracts import (
9
9
  Event,
10
+ EventType,
10
11
  InvariantViolation,
11
12
  NewEvent,
12
13
  SurfaceOp,
@@ -69,7 +70,11 @@ class InMemoryEventStore:
69
70
  return tuple(
70
71
  copy.deepcopy(event)
71
72
  for event in events
72
- if event.seq >= epoch_seq and event.surface_op != SurfaceOp.NONE
73
+ if event.seq >= epoch_seq
74
+ and (
75
+ event.surface_op != SurfaceOp.NONE
76
+ or event.event_type == EventType.TOOL_BATCH_REJECTED
77
+ )
73
78
  )
74
79
 
75
80
  async def load_recovery(self, session_id: str) -> Sequence[Event]:
@@ -173,7 +173,7 @@ class SQLiteEventStore:
173
173
  SELECT MAX(seq) FROM session_events
174
174
  WHERE session_id = ? AND surface_op = 'epoch'
175
175
  ), 1)
176
- AND surface_op != 'none'
176
+ AND (surface_op != 'none' OR event_type = 'tool/batch-rejected')
177
177
  ORDER BY seq
178
178
  """,
179
179
  (session_id, session_id),
@@ -93,6 +93,11 @@ def project_events(
93
93
  config: LoopConfig,
94
94
  tools: Sequence[ToolSpec],
95
95
  ) -> Projection:
96
+ rejected_steps = {
97
+ (event.turn, event.step)
98
+ for event in events
99
+ if event.event_type == EventType.TOOL_BATCH_REJECTED
100
+ }
96
101
  messages = [Message(role="system", content=config.system_prompt)]
97
102
  messages.extend(config.bootstrap_messages)
98
103
  for event in events:
@@ -105,7 +110,19 @@ def project_events(
105
110
  EventType.ASSISTANT_MESSAGE,
106
111
  EventType.TOOL_RESULT,
107
112
  ):
108
- messages.append(message_from_data(event.payload["message"]))
113
+ message = message_from_data(event.payload["message"])
114
+ if (
115
+ event.event_type == EventType.ASSISTANT_MESSAGE
116
+ and (event.turn, event.step) in rejected_steps
117
+ ):
118
+ if not message.content:
119
+ continue
120
+ message = Message(
121
+ role=message.role,
122
+ content=message.content,
123
+ provider_data=message.provider_data,
124
+ )
125
+ messages.append(message)
109
126
  request = CandidateRequest(
110
127
  session_id=session_id,
111
128
  turn=turn,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextloop
3
- Version: 0.1.0rc1
3
+ Version: 0.1.0rc2
4
4
  Summary: An embeddable AgentLoop with explicit event, tool, recovery, and delivery semantics
5
5
  Author-email: 12bitsD <bis12@163.com>
6
6
  License-Expression: MIT
@@ -30,12 +30,12 @@ Dynamic: license-file
30
30
 
31
31
  A small, embeddable Python AgentLoop with explicit execution, recovery, and delivery semantics.
32
32
 
33
- Current version: **0.1.0rc1**.
33
+ Current version: **0.1.0rc2**.
34
34
 
35
35
  ## Install
36
36
 
37
37
  ```bash
38
- python -m pip install nextloop==0.1.0rc1
38
+ python -m pip install nextloop==0.1.0rc2
39
39
  ```
40
40
 
41
41
  For local development:
@@ -123,11 +123,12 @@ The release-candidate checks cover:
123
123
  - resource-lock recovery, conflict prevention, and explicit release;
124
124
  - real subprocess exits during Tool execution and final delivery, followed by SQLite recovery;
125
125
  - recorded OpenAI and Anthropic SSE streams;
126
+ - 12 live Kimi scenarios across both protocols, real Tool usage, parallel execution, recovery, steer, cancellation, Compaction, and WorkingContext;
126
127
  - `ruff`, `mypy`, wheel/sdist builds, `twine check`, and clean wheel installation.
127
128
 
128
129
  Current limits:
129
130
 
130
- - Hosted-model smoke and nika integration are separate acceptance work.
131
+ - nika integration is separate acceptance work.
131
132
  - Concurrent writers across multiple processes fail closed; they are not coordinated.
132
133
  - Large-asset lifecycle, backup, and GC are not part of this release candidate.
133
134
 
@@ -117,6 +117,9 @@ async def test_invalid_batch_executes_nothing_then_corrects():
117
117
  events = await store.load_recovery("s")
118
118
  assert any(event.event_type == EventType.TOOL_BATCH_REJECTED for event in events)
119
119
  assert not any(event.event_type == EventType.TOOL_CALL for event in events)
120
+ second_request = provider.requests[1]
121
+ assert all(not message.tool_calls for message in second_request.messages)
122
+ assert second_request.messages[-1].content.startswith("[Protocol correction]")
120
123
 
121
124
 
122
125
  @pytest.mark.asyncio
File without changes
File without changes