wepscli 0.1.0 → 0.1.5
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.
- package/README.md +9 -8
- package/dist/WEPSCLI-shell/agent-runtime-events.js +194 -0
- package/dist/WEPSCLI-shell/agent-runtime-events.js.map +1 -0
- package/dist/WEPSCLI-shell/agent-runtime-helpers.js +117 -0
- package/dist/WEPSCLI-shell/agent-runtime-helpers.js.map +1 -0
- package/dist/WEPSCLI-shell/agent-runtime-types.js +1 -0
- package/dist/WEPSCLI-shell/agent-runtime-types.js.map +1 -0
- package/dist/WEPSCLI-shell/agent-runtime.js +42 -294
- package/dist/WEPSCLI-shell/agent-runtime.js.map +1 -1
- package/dist/WEPSCLI-shell/approval-overlay.js.map +1 -1
- package/dist/WEPSCLI-shell/chat-components.js +13 -6
- package/dist/WEPSCLI-shell/chat-components.js.map +1 -1
- package/dist/WEPSCLI-shell/file-change-preview.js.map +1 -1
- package/dist/WEPSCLI-shell/runtime-recovery.js.map +1 -1
- package/dist/WEPSCLI-shell/session-consistency.js +9 -0
- package/dist/WEPSCLI-shell/session-consistency.js.map +1 -0
- package/dist/WEPSCLI-shell/shell-app.js +169 -259
- package/dist/WEPSCLI-shell/shell-app.js.map +1 -1
- package/dist/WEPSCLI-shell/shell-keyboard.js +135 -0
- package/dist/WEPSCLI-shell/shell-keyboard.js.map +1 -0
- package/dist/WEPSCLI-shell/shell-modes.js.map +1 -1
- package/dist/WEPSCLI-shell/shell-prompt-controller.js +93 -0
- package/dist/WEPSCLI-shell/shell-prompt-controller.js.map +1 -0
- package/dist/WEPSCLI-shell/shell-status.js +16 -0
- package/dist/WEPSCLI-shell/shell-status.js.map +1 -0
- package/dist/WEPSCLI-shell/skill-commands.js +7 -0
- package/dist/WEPSCLI-shell/skill-commands.js.map +1 -0
- package/dist/WEPSCLI-shell/slash-commands.js +68 -7
- package/dist/WEPSCLI-shell/slash-commands.js.map +1 -1
- package/dist/WEPSCLI-shell/tool-approval.js.map +1 -1
- package/dist/WEPSCLI-shell/tool-diff.js.map +1 -1
- package/dist/WEPSCLI-shell/tool-file-changes.js.map +1 -1
- package/dist/WEPSCLI-shell/tool-message-detail.js.map +1 -1
- package/dist/WEPSCLI-shell/tool-messages.js.map +1 -1
- package/dist/WEPSCLI-shell/transcript-panel.js.map +1 -1
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/main.js.map +1 -1
- package/dist/skills/skill-add-flow.js +88 -0
- package/dist/skills/skill-add-flow.js.map +1 -0
- package/dist/skills/skill-service.js +123 -0
- package/dist/skills/skill-service.js.map +1 -0
- package/package.json +28 -24
|
@@ -1,118 +1,11 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { getAgentDir } from "../config.js";
|
|
3
|
-
import {
|
|
3
|
+
import { handleAgentSessionEvent } from "./agent-runtime-events.js";
|
|
4
|
+
import { cancellationToolOutput, createMessageId, extractAssistantReasoning, extractAssistantVisibleText, extractUserText, formatCompactionResultMessage, formatRuntimeError, formatTime, getRuntimeSessionDir, installBeforeToolCallHook, loadCodingAgentRuntime, toModelDefinition } from "./agent-runtime-helpers.js";
|
|
5
|
+
import { createCompactingRuntimeState, createErrorRuntimeState, createIdleRuntimeState, createInterruptedRuntimeState, createRunningRuntimeState } from "./runtime-status.js";
|
|
4
6
|
import { getRuntimeRecoveryHint } from "./runtime-recovery.js";
|
|
5
7
|
import { createToolApprovalRequest, toolApprovalDecisionReason } from "./tool-approval.js";
|
|
6
8
|
import { createToolMessageState, updateToolMessageState } from "./tool-messages.js";
|
|
7
|
-
let codingAgentRuntimePromise;
|
|
8
|
-
async function loadCodingAgentRuntime() {
|
|
9
|
-
if (!codingAgentRuntimePromise) {
|
|
10
|
-
codingAgentRuntimePromise = import("@mariozechner/pi-coding-agent").then(module => module);
|
|
11
|
-
}
|
|
12
|
-
return codingAgentRuntimePromise;
|
|
13
|
-
}
|
|
14
|
-
function formatTime(timestamp) {
|
|
15
|
-
return new Date(timestamp ?? Date.now()).toLocaleTimeString("en-US", {
|
|
16
|
-
hour: "2-digit",
|
|
17
|
-
minute: "2-digit"
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
function createMessageId(record, role) {
|
|
21
|
-
record.sequence += 1;
|
|
22
|
-
return `runtime:${role}:${record.sequence}`;
|
|
23
|
-
}
|
|
24
|
-
function guessReasoningSupport(modelId) {
|
|
25
|
-
const value = modelId.toLowerCase();
|
|
26
|
-
return ["gpt-5", "gpt-4.1", "o1", "o3", "o4", "claude-3-7", "claude-sonnet-4", "claude-opus-4", "gemini-2.5", "reasoner", "thinking"].some(token => value.includes(token));
|
|
27
|
-
}
|
|
28
|
-
function extractTextBlocks(content) {
|
|
29
|
-
return content.map(item => {
|
|
30
|
-
if (item.type === "text" && typeof item.text === "string") {
|
|
31
|
-
return item.text;
|
|
32
|
-
}
|
|
33
|
-
if (item.type === "image") {
|
|
34
|
-
return "[image]";
|
|
35
|
-
}
|
|
36
|
-
if (item.type === "thinking" && typeof item.thinking === "string") {
|
|
37
|
-
return item.thinking;
|
|
38
|
-
}
|
|
39
|
-
return "";
|
|
40
|
-
}).filter(Boolean).join("\n\n");
|
|
41
|
-
}
|
|
42
|
-
function extractUserText(message) {
|
|
43
|
-
if (typeof message.content === "string") {
|
|
44
|
-
return message.content;
|
|
45
|
-
}
|
|
46
|
-
return extractTextBlocks(message.content);
|
|
47
|
-
}
|
|
48
|
-
function extractAssistantVisibleText(message) {
|
|
49
|
-
const text = extractTextBlocks(message.content.filter(item => item.type === "text").map(item => ({
|
|
50
|
-
type: item.type,
|
|
51
|
-
text: item.text
|
|
52
|
-
})));
|
|
53
|
-
if (text) {
|
|
54
|
-
return text;
|
|
55
|
-
}
|
|
56
|
-
if (message.errorMessage) {
|
|
57
|
-
return message.errorMessage;
|
|
58
|
-
}
|
|
59
|
-
return "";
|
|
60
|
-
}
|
|
61
|
-
function extractAssistantReasoning(message) {
|
|
62
|
-
return extractTextBlocks(message.content.filter(item => item.type === "thinking").map(item => ({
|
|
63
|
-
type: item.type,
|
|
64
|
-
thinking: item.thinking
|
|
65
|
-
})));
|
|
66
|
-
}
|
|
67
|
-
function formatRuntimeError(error) {
|
|
68
|
-
return error instanceof Error ? error.message : String(error);
|
|
69
|
-
}
|
|
70
|
-
function formatCompactionResultMessage(result) {
|
|
71
|
-
if (typeof result.tokensBefore === "number" && Number.isFinite(result.tokensBefore)) {
|
|
72
|
-
return `Context compacted from ${result.tokensBefore.toLocaleString("en-US")} tokens.`;
|
|
73
|
-
}
|
|
74
|
-
return "Context compacted.";
|
|
75
|
-
}
|
|
76
|
-
function cancellationToolOutput(reason) {
|
|
77
|
-
return {
|
|
78
|
-
content: [{
|
|
79
|
-
type: "text",
|
|
80
|
-
text: reason
|
|
81
|
-
}]
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function toModelDefinition(model) {
|
|
85
|
-
return {
|
|
86
|
-
id: model.id,
|
|
87
|
-
name: model.name,
|
|
88
|
-
reasoning: guessReasoningSupport(model.id),
|
|
89
|
-
input: ["text", "image"],
|
|
90
|
-
cost: {
|
|
91
|
-
input: 0,
|
|
92
|
-
output: 0,
|
|
93
|
-
cacheRead: 0,
|
|
94
|
-
cacheWrite: 0
|
|
95
|
-
},
|
|
96
|
-
contextWindow: 128_000,
|
|
97
|
-
maxTokens: 16_384
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
function getRuntimeSessionDir(cwd, agentDir) {
|
|
101
|
-
const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
102
|
-
return join(agentDir, "sessions", safePath);
|
|
103
|
-
}
|
|
104
|
-
function installBeforeToolCallHook(session, handler) {
|
|
105
|
-
if (typeof session.addBeforeToolCall === "function") {
|
|
106
|
-
return session.addBeforeToolCall(handler);
|
|
107
|
-
}
|
|
108
|
-
if (typeof session.agent?.setBeforeToolCall === "function") {
|
|
109
|
-
session.agent.setBeforeToolCall(handler);
|
|
110
|
-
return () => {
|
|
111
|
-
session.agent.setBeforeToolCall?.(undefined);
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
throw new Error("The installed pi-coding-agent runtime does not expose a before-tool-call hook API.");
|
|
115
|
-
}
|
|
116
9
|
export class WepsAgentRuntime {
|
|
117
10
|
records = new Map();
|
|
118
11
|
pending = new Map();
|
|
@@ -209,6 +102,31 @@ export class WepsAgentRuntime {
|
|
|
209
102
|
this.applyRecoveryState(sessionId, record, message, "Selection failed - ready");
|
|
210
103
|
}
|
|
211
104
|
}
|
|
105
|
+
async reload(sessionId, selection, binding = {}) {
|
|
106
|
+
const record = await this.ensureSession(sessionId, selection, binding);
|
|
107
|
+
const reloadableSession = record.session;
|
|
108
|
+
if (typeof reloadableSession.reload !== "function") {
|
|
109
|
+
this.appendSystemMessage(sessionId, record, "Resource reload is not available in the current runtime.");
|
|
110
|
+
this.setRuntimeState(sessionId, record, createErrorRuntimeState("Reload unavailable - ready"));
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
record.activePrompts += 1;
|
|
114
|
+
this.setRuntimeState(sessionId, record, createRunningRuntimeState("Reloading resources"));
|
|
115
|
+
try {
|
|
116
|
+
await this.applySelection(record, selection);
|
|
117
|
+
await reloadableSession.reload();
|
|
118
|
+
this.setRuntimeState(sessionId, record, createIdleRuntimeState());
|
|
119
|
+
return true;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
const message = formatRuntimeError(error);
|
|
122
|
+
this.appendSystemMessage(sessionId, record, `Reload failed: ${message}`);
|
|
123
|
+
this.applyRecoveryState(sessionId, record, message, "Reload failed - ready");
|
|
124
|
+
return false;
|
|
125
|
+
} finally {
|
|
126
|
+
record.activePrompts = Math.max(0, record.activePrompts - 1);
|
|
127
|
+
this.resetRuntimeStateAfterActivity(sessionId, record);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
212
130
|
setMode(mode) {
|
|
213
131
|
this.currentMode = mode;
|
|
214
132
|
}
|
|
@@ -284,7 +202,9 @@ export class WepsAgentRuntime {
|
|
|
284
202
|
switchSession: async () => ({
|
|
285
203
|
cancelled: true
|
|
286
204
|
}),
|
|
287
|
-
reload: async () => {
|
|
205
|
+
reload: async () => {
|
|
206
|
+
await session.reload?.();
|
|
207
|
+
}
|
|
288
208
|
},
|
|
289
209
|
onError: error => {
|
|
290
210
|
const record = this.records.get(sessionId);
|
|
@@ -637,188 +557,16 @@ export class WepsAgentRuntime {
|
|
|
637
557
|
};
|
|
638
558
|
}
|
|
639
559
|
handleSessionEvent(sessionId, record, event) {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
if (event.message.role === "assistant") {
|
|
655
|
-
record.streamingAssistantMessageId = undefined;
|
|
656
|
-
record.streamingReasoningMessageId = undefined;
|
|
657
|
-
}
|
|
658
|
-
return;
|
|
659
|
-
case "message_update":
|
|
660
|
-
if (event.assistantMessageEvent.type === "thinking_delta") {
|
|
661
|
-
if (!record.streamingReasoningMessageId) {
|
|
662
|
-
record.streamingReasoningMessageId = record.streamingAssistantMessageId ? this.insertReasoningMessageBefore(sessionId, record, record.streamingAssistantMessageId, event.assistantMessageEvent.delta) : (() => {
|
|
663
|
-
const id = createMessageId(record, "assistant");
|
|
664
|
-
this.callbacks.appendMessage(sessionId, {
|
|
665
|
-
id,
|
|
666
|
-
role: "assistant",
|
|
667
|
-
content: event.assistantMessageEvent.delta,
|
|
668
|
-
time: formatTime(),
|
|
669
|
-
kind: "reasoning",
|
|
670
|
-
collapsible: true,
|
|
671
|
-
expanded: false
|
|
672
|
-
});
|
|
673
|
-
return id;
|
|
674
|
-
})();
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
this.callbacks.patchMessage(sessionId, record.streamingReasoningMessageId, {
|
|
678
|
-
appendContent: event.assistantMessageEvent.delta
|
|
679
|
-
});
|
|
680
|
-
return;
|
|
681
|
-
}
|
|
682
|
-
if (event.assistantMessageEvent.type === "text_delta" && record.streamingAssistantMessageId) {
|
|
683
|
-
this.callbacks.patchMessage(sessionId, record.streamingAssistantMessageId, {
|
|
684
|
-
appendContent: event.assistantMessageEvent.delta
|
|
685
|
-
});
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
if (event.assistantMessageEvent.type === "text_delta") {
|
|
689
|
-
const messageId = createMessageId(record, "assistant");
|
|
690
|
-
record.streamingAssistantMessageId = messageId;
|
|
691
|
-
this.callbacks.appendMessage(sessionId, {
|
|
692
|
-
id: messageId,
|
|
693
|
-
role: "assistant",
|
|
694
|
-
content: event.assistantMessageEvent.delta,
|
|
695
|
-
time: formatTime()
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
return;
|
|
699
|
-
case "message_end":
|
|
700
|
-
if (event.message.role === "assistant") {
|
|
701
|
-
const finalMessage = event.message;
|
|
702
|
-
const content = extractAssistantVisibleText(finalMessage);
|
|
703
|
-
const reasoning = extractAssistantReasoning(finalMessage);
|
|
704
|
-
const messageId = record.streamingAssistantMessageId;
|
|
705
|
-
const reasoningMessageId = record.streamingReasoningMessageId;
|
|
706
|
-
record.streamingAssistantMessageId = undefined;
|
|
707
|
-
record.streamingReasoningMessageId = undefined;
|
|
708
|
-
if (messageId) {
|
|
709
|
-
this.callbacks.patchMessage(sessionId, messageId, {
|
|
710
|
-
content,
|
|
711
|
-
time: formatTime(finalMessage.timestamp)
|
|
712
|
-
});
|
|
713
|
-
} else if (content) {
|
|
714
|
-
this.callbacks.appendMessage(sessionId, {
|
|
715
|
-
id: createMessageId(record, "assistant"),
|
|
716
|
-
role: "assistant",
|
|
717
|
-
content,
|
|
718
|
-
time: formatTime(finalMessage.timestamp)
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
if (reasoning) {
|
|
722
|
-
if (reasoningMessageId) {
|
|
723
|
-
this.callbacks.patchMessage(sessionId, reasoningMessageId, {
|
|
724
|
-
content: reasoning,
|
|
725
|
-
time: formatTime(finalMessage.timestamp)
|
|
726
|
-
});
|
|
727
|
-
} else if (messageId) {
|
|
728
|
-
this.insertReasoningMessageBefore(sessionId, record, messageId, reasoning);
|
|
729
|
-
} else {
|
|
730
|
-
this.appendReasoningMessage(sessionId, record, reasoning);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
if (finalMessage.stopReason === "aborted") {
|
|
734
|
-
this.setRuntimeState(sessionId, record, createInterruptedRuntimeState("Interrupted - ready", "The current request was cancelled."));
|
|
735
|
-
} else if (finalMessage.stopReason === "error" && finalMessage.errorMessage) {
|
|
736
|
-
this.applyRecoveryState(sessionId, record, finalMessage.errorMessage, "Request failed - ready");
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
return;
|
|
740
|
-
case "tool_execution_start":
|
|
741
|
-
{
|
|
742
|
-
const tool = createToolMessageState(event.toolCallId, event.toolName, event.args);
|
|
743
|
-
const messageId = this.appendToolMessage(sessionId, record, tool);
|
|
744
|
-
record.toolMessageIds.set(event.toolCallId, messageId);
|
|
745
|
-
record.toolStates.set(event.toolCallId, tool);
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
case "tool_execution_update":
|
|
749
|
-
{
|
|
750
|
-
const messageId = record.toolMessageIds.get(event.toolCallId);
|
|
751
|
-
const tool = record.toolStates.get(event.toolCallId);
|
|
752
|
-
if (!messageId || !tool) {
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
const nextTool = updateToolMessageState(tool, {
|
|
756
|
-
args: event.args,
|
|
757
|
-
output: event.partialResult
|
|
758
|
-
});
|
|
759
|
-
record.toolStates.set(event.toolCallId, nextTool);
|
|
760
|
-
this.callbacks.patchMessage(sessionId, messageId, {
|
|
761
|
-
tool: nextTool
|
|
762
|
-
});
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
case "tool_execution_end":
|
|
766
|
-
{
|
|
767
|
-
const messageId = record.toolMessageIds.get(event.toolCallId);
|
|
768
|
-
const tool = record.toolStates.get(event.toolCallId);
|
|
769
|
-
record.toolMessageIds.delete(event.toolCallId);
|
|
770
|
-
record.toolStates.delete(event.toolCallId);
|
|
771
|
-
const nextTool = updateToolMessageState(tool ?? createToolMessageState(event.toolCallId, event.toolName, undefined), {
|
|
772
|
-
status: event.isError ? "failed" : "completed",
|
|
773
|
-
output: event.result
|
|
774
|
-
});
|
|
775
|
-
if (messageId) {
|
|
776
|
-
this.callbacks.patchMessage(sessionId, messageId, {
|
|
777
|
-
tool: nextTool,
|
|
778
|
-
time: formatTime()
|
|
779
|
-
});
|
|
780
|
-
return;
|
|
781
|
-
}
|
|
782
|
-
this.appendToolMessage(sessionId, record, nextTool);
|
|
783
|
-
return;
|
|
784
|
-
}
|
|
785
|
-
case "auto_compaction_start":
|
|
786
|
-
this.setRuntimeState(sessionId, record, createCompactingRuntimeState(event.reason === "overflow" ? "Compacting after overflow" : "Compacting context"));
|
|
787
|
-
this.appendSystemMessage(sessionId, record, "Compacting context...");
|
|
788
|
-
return;
|
|
789
|
-
case "auto_compaction_end":
|
|
790
|
-
if (event.errorMessage) {
|
|
791
|
-
this.applyRecoveryState(sessionId, record, event.errorMessage, "Compaction failed - ready");
|
|
792
|
-
} else if (event.aborted) {
|
|
793
|
-
this.setRuntimeState(sessionId, record, createInterruptedRuntimeState("Compaction cancelled - ready", "You can continue with a new prompt."));
|
|
794
|
-
} else if (event.willRetry) {
|
|
795
|
-
this.setRuntimeState(sessionId, record, createRetryingRuntimeState("Retrying after compaction"));
|
|
796
|
-
} else if (record.activePrompts > 0) {
|
|
797
|
-
this.setRuntimeState(sessionId, record, createRunningRuntimeState());
|
|
798
|
-
}
|
|
799
|
-
this.appendSystemMessage(sessionId, record, event.errorMessage ? `Compaction failed: ${event.errorMessage}` : event.aborted ? "Compaction aborted." : event.result ? "Context compacted." : "Compaction skipped.");
|
|
800
|
-
return;
|
|
801
|
-
case "auto_retry_start":
|
|
802
|
-
this.setRuntimeState(sessionId, record, createRetryingRuntimeState(`Retrying (${event.attempt}/${event.maxAttempts})`, event.errorMessage));
|
|
803
|
-
this.appendSystemMessage(sessionId, record, `Retrying request (${event.attempt}/${event.maxAttempts}) after error: ${event.errorMessage}`);
|
|
804
|
-
return;
|
|
805
|
-
case "auto_retry_end":
|
|
806
|
-
if (!event.success) {
|
|
807
|
-
const finalError = event.finalError ?? "Retry cancelled";
|
|
808
|
-
this.setRuntimeState(sessionId, record, finalError.toLowerCase().includes("cancel") ? createInterruptedRuntimeState("Retry cancelled - ready", finalError) : createErrorRuntimeState("Retry failed - ready", finalError));
|
|
809
|
-
this.appendSystemMessage(sessionId, record, `Retry failed: ${finalError}`);
|
|
810
|
-
if (!finalError.toLowerCase().includes("cancel")) {
|
|
811
|
-
const hint = getRuntimeRecoveryHint(finalError);
|
|
812
|
-
if (hint?.nextStep) {
|
|
813
|
-
this.appendSystemMessage(sessionId, record, hint.nextStep);
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
} else if (record.activePrompts > 0) {
|
|
817
|
-
this.setRuntimeState(sessionId, record, createRunningRuntimeState());
|
|
818
|
-
}
|
|
819
|
-
return;
|
|
820
|
-
default:
|
|
821
|
-
return;
|
|
822
|
-
}
|
|
560
|
+
handleAgentSessionEvent(event, {
|
|
561
|
+
sessionId,
|
|
562
|
+
record,
|
|
563
|
+
callbacks: this.callbacks,
|
|
564
|
+
appendToolMessage: tool => this.appendToolMessage(sessionId, record, tool),
|
|
565
|
+
appendReasoningMessage: content => this.appendReasoningMessage(sessionId, record, content),
|
|
566
|
+
insertReasoningMessageBefore: (beforeMessageId, content) => this.insertReasoningMessageBefore(sessionId, record, beforeMessageId, content),
|
|
567
|
+
appendSystemMessage: content => this.appendSystemMessage(sessionId, record, content),
|
|
568
|
+
applyRecoveryState: (message, fallbackLabel) => this.applyRecoveryState(sessionId, record, message, fallbackLabel),
|
|
569
|
+
setRuntimeState: state => this.setRuntimeState(sessionId, record, state)
|
|
570
|
+
});
|
|
823
571
|
}
|
|
824
572
|
}
|