@oyasmi/pipiclaw 0.6.6-beta.1 → 0.6.6-beta.2

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.
@@ -25,6 +25,7 @@ export declare class ChannelRunner implements AgentRunner {
25
25
  private currentSkills;
26
26
  private firstTurnMemoryBootstrapPending;
27
27
  private acceptingBusyMessages;
28
+ private agentLoopStarted;
28
29
  private runState;
29
30
  constructor(sandboxConfig: SandboxConfig, channelId: string, channelDir: string);
30
31
  run(ctx: DingTalkContext, store: ChannelStore): Promise<{
@@ -54,6 +54,7 @@ export class ChannelRunner {
54
54
  constructor(sandboxConfig, channelId, channelDir) {
55
55
  this.firstTurnMemoryBootstrapPending = true;
56
56
  this.acceptingBusyMessages = false;
57
+ this.agentLoopStarted = false;
57
58
  // --- Per run ---
58
59
  this.runState = createEmptyRunState();
59
60
  this.sandboxConfig = sandboxConfig;
@@ -171,6 +172,7 @@ export class ChannelRunner {
171
172
  async run(ctx, store) {
172
173
  this.resetRunState(ctx, store);
173
174
  this.acceptingBusyMessages = true;
175
+ this.agentLoopStarted = false;
174
176
  const runQueue = createRunQueue(ctx);
175
177
  this.runState.queue = runQueue.queue;
176
178
  let promptSubmitted = false;
@@ -238,6 +240,7 @@ export class ChannelRunner {
238
240
  }
239
241
  finally {
240
242
  this.acceptingBusyMessages = false;
243
+ this.agentLoopStarted = false;
241
244
  if (!promptSubmitted) {
242
245
  const discarded = this.session.clearQueue();
243
246
  const discardedCount = discarded.steering.length + discarded.followUp.length;
@@ -438,6 +441,9 @@ export class ChannelRunner {
438
441
  if (!this.acceptingBusyMessages) {
439
442
  throw new Error("No task is currently running.");
440
443
  }
444
+ if (this.agentLoopStarted && !this.session.isStreaming) {
445
+ throw new Error("No task is currently running.");
446
+ }
441
447
  await this.ensureSessionReady();
442
448
  const clippedText = clipUserInput(text, MAX_USER_MESSAGE_CHARS);
443
449
  if (clippedText !== text.trim()) {
@@ -448,7 +454,13 @@ export class ChannelRunner {
448
454
  if (!this.acceptingBusyMessages) {
449
455
  throw new Error("No task is currently running.");
450
456
  }
457
+ if (this.agentLoopStarted && !this.session.isStreaming) {
458
+ throw new Error("No task is currently running.");
459
+ }
451
460
  const queueMessage = async () => {
461
+ if (this.agentLoopStarted && !this.session.isStreaming) {
462
+ throw new Error("No task is currently running.");
463
+ }
452
464
  if (delivery === "followUp") {
453
465
  await this.session.followUp(queuedMessage);
454
466
  }
@@ -584,6 +596,9 @@ export class ChannelRunner {
584
596
  // === Session event subscription ===
585
597
  subscribeToSessionEvents() {
586
598
  this.session.subscribe(async (event) => {
599
+ if (isRecord(event) && event.type === "message_start") {
600
+ this.agentLoopStarted = true;
601
+ }
587
602
  if (isRecord(event) && "reason" in event && event.reason === "new") {
588
603
  this.firstTurnMemoryBootstrapPending = true;
589
604
  }
@@ -127,6 +127,7 @@ export async function handleSessionEvent(event, context) {
127
127
  const commandResultText = extractCustomCommandResultText(event.message);
128
128
  if (commandResultText) {
129
129
  runState.finalOutcome = { kind: "final", text: commandResultText };
130
+ runState.finalResponseDelivered = false;
130
131
  log.logResponse(logCtx, commandResultText);
131
132
  queue.enqueue(async () => {
132
133
  const delivered = await ctx.respondPlain(commandResultText);
@@ -195,6 +196,7 @@ export async function handleSessionEvent(event, context) {
195
196
  return;
196
197
  }
197
198
  runState.finalOutcome = { kind: "final", text: finalText };
199
+ runState.finalResponseDelivered = false;
198
200
  memoryLifecycle.noteCompletedAssistantTurn();
199
201
  log.logResponse(logCtx, finalText);
200
202
  queue.enqueue(async () => {
@@ -96,10 +96,28 @@ class ChannelDeliveryController {
96
96
  log.logWarning(`[${this.event.channelId}] Failed to archive bot response`, err instanceof Error ? err.message : String(err));
97
97
  });
98
98
  }
99
+ resetProgressAfterFinal() {
100
+ if (!this.finalResponseDelivered) {
101
+ return;
102
+ }
103
+ this.progressSegments = [];
104
+ this.cachedProgressText = "";
105
+ this.progressTextDirty = false;
106
+ this.mode = "progress";
107
+ this.progressStartedAt = 0;
108
+ this.progressWindowStartedAt = 0;
109
+ this.toolCallCount = 0;
110
+ this.sentProgressChars = 0;
111
+ this.replayRequired = false;
112
+ this.finalReplacementText = "";
113
+ this.cardWarmupTriggered = false;
114
+ this.finalResponseDelivered = false;
115
+ }
99
116
  async appendProgress(text, shouldLog) {
100
- if (this.closed || this.finalResponseDelivered || !text.trim())
117
+ if (this.closed || !text.trim())
101
118
  return;
102
119
  this.clearCardWarmup();
120
+ this.resetProgressAfterFinal();
103
121
  if (this.progressStartedAt === 0) {
104
122
  this.progressStartedAt = Date.now();
105
123
  }
@@ -124,8 +142,8 @@ class ChannelDeliveryController {
124
142
  this.bumpRevision(false);
125
143
  }
126
144
  async sendFinal(text, shouldLog) {
127
- if (this.closed || this.finalResponseDelivered)
128
- return this.finalResponseDelivered;
145
+ if (this.closed)
146
+ return false;
129
147
  this.clearCardWarmup();
130
148
  if (shouldLog) {
131
149
  this.archiveBotResponse(text);
@@ -140,7 +158,7 @@ class ChannelDeliveryController {
140
158
  return true;
141
159
  }
142
160
  async replaceWithFinal(text) {
143
- if (this.closed || this.finalResponseDelivered)
161
+ if (this.closed)
144
162
  return;
145
163
  this.clearCardWarmup();
146
164
  this.finalReplacementText = text;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oyasmi/pipiclaw",
3
- "version": "0.6.6-beta.1",
3
+ "version": "0.6.6-beta.2",
4
4
  "description": "An AI assistant runtime for coding and team workflows, with DingTalk AI Cards, sub-agents, memory, and scheduled events.",
5
5
  "type": "module",
6
6
  "bin": {