@brandon_9527/tcode 1.0.10 → 1.0.11
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/dist/python-src/main.py +2 -2
- package/dist/python-src/src/claw/channels/feishu.py +10 -10
- package/dist/python-src/src/claw/cron/service.py +25 -25
- package/dist/python-src/src/claw/heartbeat/service.py +4 -4
- package/dist/python-src/src/core/context.py +11 -11
- package/dist/python-src/src/managers/manager_agent.py +9 -9
- package/dist/python-src/src/managers/manager_instruction.py +7 -7
- package/dist/python-src/src/managers/sandbox.py +3 -3
- package/dist/python-src/src/middlewares/subagents.py +4 -4
- package/dist/python-src/src/middlewares/summary.py +34 -34
- package/dist/python-src/src/stream/formatter.py +19 -19
- package/dist/python-src/src/stream/handler.py +4 -4
- package/dist/python-src/src/stream/handler_with_tracker.py +10 -10
- package/dist/python-src/src/trackers/token/report.py +2 -2
- package/dist/python-src/src/tui/chatui.py +7 -7
- package/dist/python-src/src/tui/clawtui.py +9 -9
- package/dist/python-src/src/tui/components/tlist.py +5 -5
- package/dist/python-src/src/tui/components/tscroll_panel.py +10 -10
- package/dist/python-src/src/tui/utils/trender.py +21 -21
- package/package.json +1 -1
|
@@ -27,7 +27,7 @@ ContextFraction=tuple[Literal[_D],float]
|
|
|
27
27
|
ContextTokens=tuple[Literal[_E],int]
|
|
28
28
|
ContextMessages=tuple[Literal[_B],int]
|
|
29
29
|
ContextSize=ContextFraction|ContextTokens|ContextMessages
|
|
30
|
-
def
|
|
30
|
+
def de(model):
|
|
31
31
|
if model._llm_type=='anthropic-chat':return partial(count_tokens_approximately,chars_per_token=3.3)
|
|
32
32
|
return count_tokens_approximately
|
|
33
33
|
class SummaryState(AgentState):compact:NotRequired[bool]=_F
|
|
@@ -44,30 +44,30 @@ class SummarizationMiddleware(AgentMiddleware):
|
|
|
44
44
|
if isinstance(C,str):C=init_chat_model(C)
|
|
45
45
|
A.model=C
|
|
46
46
|
if B is _A:A.trigger=_A;G=[]
|
|
47
|
-
elif isinstance(B,list):I=[A.
|
|
48
|
-
else:J=A.
|
|
49
|
-
A._trigger_conditions=G;A.keep=A.
|
|
50
|
-
if H is count_tokens_approximately:A.token_counter=
|
|
47
|
+
elif isinstance(B,list):I=[A.da(B,N)for B in B];A.trigger=I;G=I
|
|
48
|
+
else:J=A.da(B,N);A.trigger=J;G=[J]
|
|
49
|
+
A._trigger_conditions=G;A.keep=A.da(F,'keep')
|
|
50
|
+
if H is count_tokens_approximately:A.token_counter=de(A.model)
|
|
51
51
|
else:A.token_counter=H
|
|
52
52
|
A.summary_prompt=summary_prompt;A.trim_tokens_to_summarize=trim_tokens_to_summarize;K=any(A[0]==_D for A in A._trigger_conditions)
|
|
53
53
|
if A.keep[0]==_D:K=_C
|
|
54
|
-
if K and A.
|
|
55
|
-
def
|
|
54
|
+
if K and A.dk()is _A:O='Model profile information is required to use fractional token limits, and is unavailable for the specified model. Please use absolute token counts instead, or pass `\n\nChatModel(..., profile={"max_input_tokens": ...})`.\n\nwith a desired integer value of the model\'s maximum input tokens.';raise ValueError(O)
|
|
55
|
+
def dh(B,state):A=state.get(_G,_F);return bool(A)
|
|
56
56
|
@override
|
|
57
57
|
def before_model(self,state,runtime):
|
|
58
|
-
C=state;A=self;B=C[_B];A.dc(B);E=A.token_counter(B);F=A.
|
|
58
|
+
C=state;A=self;B=C[_B];A.dc(B);E=A.token_counter(B);F=A.dh(C);G=A.do(B,E)
|
|
59
59
|
if not G and not F:return
|
|
60
|
-
D=A.
|
|
60
|
+
D=A.dg(B)
|
|
61
61
|
if D<=0:return
|
|
62
|
-
H,I=A.
|
|
62
|
+
H,I=A.df(B,D);J=A.dm(H);K=A.dn(J);return{_B:[RemoveMessage(id=REMOVE_ALL_MESSAGES),*K,*I],_G:_F}
|
|
63
63
|
@override
|
|
64
64
|
async def abefore_model(self,state,runtime):
|
|
65
|
-
C=state;A=self;B=C[_B];A.dc(B);E=A.token_counter(B);F=A.
|
|
65
|
+
C=state;A=self;B=C[_B];A.dc(B);E=A.token_counter(B);F=A.dh(C);G=A.do(B,E)
|
|
66
66
|
if not G and not F:return
|
|
67
|
-
D=A.
|
|
67
|
+
D=A.dg(B)
|
|
68
68
|
if D<=0:return
|
|
69
|
-
H,I=A.
|
|
70
|
-
def
|
|
69
|
+
H,I=A.df(B,D);J=await A._acreate_summary(H);K=A.dn(J);return{_B:[RemoveMessage(id=REMOVE_ALL_MESSAGES),*K,*I],_G:_F}
|
|
70
|
+
def dj(B,messages,threshold):
|
|
71
71
|
A=next((A for A in reversed(messages)if isinstance(A,AIMessage)),_A)
|
|
72
72
|
if isinstance(A,AIMessage)and A.usage_metadata is not _A and(C:=A.usage_metadata.get('total_tokens',-1))and C>=threshold and(D:=A.response_metadata.get('model_provider'))and D==B.model._get_ls_params().get('ls_provider'):return _C
|
|
73
73
|
return _F
|
|
@@ -77,28 +77,28 @@ class SummarizationMiddleware(AgentMiddleware):
|
|
|
77
77
|
for(B,C)in A._trigger_conditions:
|
|
78
78
|
if B==_B and len(E)>=C:return _C
|
|
79
79
|
if B==_E and F>=C:return _C
|
|
80
|
-
if B==_E and A.
|
|
80
|
+
if B==_E and A.dj(E,C):return _C
|
|
81
81
|
if B==_D:
|
|
82
|
-
G=A.
|
|
82
|
+
G=A.dk()
|
|
83
83
|
if G is _A:continue
|
|
84
84
|
D=int(G*C)
|
|
85
85
|
if D<=0:D=1
|
|
86
86
|
if F>=D:return _C
|
|
87
|
-
if A.
|
|
87
|
+
if A.dj(E,D):return _C
|
|
88
88
|
return _F
|
|
89
|
-
def
|
|
89
|
+
def dg(A,messages):
|
|
90
90
|
B=messages;D,E=A.keep
|
|
91
91
|
if D in{_E,_D}:
|
|
92
|
-
C=A.
|
|
92
|
+
C=A.db(B)
|
|
93
93
|
if C is not _A:return C
|
|
94
|
-
return A.
|
|
95
|
-
return A.
|
|
96
|
-
def
|
|
94
|
+
return A.dl(B,_DEFAULT_MESSAGES_TO_KEEP)
|
|
95
|
+
return A.dl(B,cast('int',E))
|
|
96
|
+
def db(C,messages):
|
|
97
97
|
A=messages
|
|
98
98
|
if not A:return 0
|
|
99
99
|
H,I=C.keep
|
|
100
100
|
if H==_D:
|
|
101
|
-
J=C.
|
|
101
|
+
J=C.dk()
|
|
102
102
|
if J is _A:return
|
|
103
103
|
F=int(J*I)
|
|
104
104
|
elif H==_E:F=int(I)
|
|
@@ -114,8 +114,8 @@ class SummarizationMiddleware(AgentMiddleware):
|
|
|
114
114
|
if B>=len(A):
|
|
115
115
|
if len(A)==1:return 0
|
|
116
116
|
B=len(A)-1
|
|
117
|
-
return C.
|
|
118
|
-
def
|
|
117
|
+
return C.dd(A,B)
|
|
118
|
+
def dk(C):
|
|
119
119
|
try:A=C.model.profile
|
|
120
120
|
except AttributeError:return
|
|
121
121
|
if not isinstance(A,Mapping):return
|
|
@@ -123,7 +123,7 @@ class SummarizationMiddleware(AgentMiddleware):
|
|
|
123
123
|
if not isinstance(B,int):return
|
|
124
124
|
return B
|
|
125
125
|
@staticmethod
|
|
126
|
-
def
|
|
126
|
+
def da(context,parameter_name):
|
|
127
127
|
E=context;C=parameter_name;D,B=E
|
|
128
128
|
if D==_D:
|
|
129
129
|
if not 0<B<=1:A=f"Fractional {C} values must be between 0 and 1, got {B}.";raise ValueError(A)
|
|
@@ -138,13 +138,13 @@ class SummarizationMiddleware(AgentMiddleware):
|
|
|
138
138
|
for A in messages:
|
|
139
139
|
if A.id is _A:A.id=str(uuid.uuid4())
|
|
140
140
|
@staticmethod
|
|
141
|
-
def
|
|
142
|
-
def
|
|
141
|
+
def df(conversation_messages,cutoff_index):B=cutoff_index;A=conversation_messages;C=A[:B];D=A[B:];return C,D
|
|
142
|
+
def dl(C,messages,messages_to_keep):
|
|
143
143
|
B=messages_to_keep;A=messages
|
|
144
144
|
if len(A)<=B:return 0
|
|
145
|
-
D=len(A)-B;return C.
|
|
145
|
+
D=len(A)-B;return C.dd(A,D)
|
|
146
146
|
@staticmethod
|
|
147
|
-
def
|
|
147
|
+
def dd(messages,cutoff_index):
|
|
148
148
|
B=cutoff_index;A=messages
|
|
149
149
|
if B>=len(A)or not isinstance(A[B],ToolMessage):return B
|
|
150
150
|
E=set();C=B
|
|
@@ -158,10 +158,10 @@ class SummarizationMiddleware(AgentMiddleware):
|
|
|
158
158
|
H={A.get('id')for A in D.tool_calls if A.get('id')}
|
|
159
159
|
if E&H:return G
|
|
160
160
|
return C
|
|
161
|
-
def
|
|
161
|
+
def dm(A,messages_to_sumarize):
|
|
162
162
|
B=messages_to_sumarize
|
|
163
163
|
if not B:return _H
|
|
164
|
-
C=A.
|
|
164
|
+
C=A.di(B)
|
|
165
165
|
if not C:return'Previous conversation was too long to summarize'
|
|
166
166
|
D=get_buffer_string(C)
|
|
167
167
|
try:E=A.model.invoke(A.summary_prompt.format(messages=D));return E.text.strip()
|
|
@@ -169,12 +169,12 @@ class SummarizationMiddleware(AgentMiddleware):
|
|
|
169
169
|
async def _acreate_summary(A,messages_to_summarize):
|
|
170
170
|
B=messages_to_summarize
|
|
171
171
|
if not B:return _H
|
|
172
|
-
C=A.
|
|
172
|
+
C=A.di(B)
|
|
173
173
|
if not C:return'Previous conversation was too long to summarize.'
|
|
174
174
|
D=get_buffer_string(C)
|
|
175
175
|
try:E=await A.model.ainvoke(A.summary_prompt.format(messages=D));return E.text.strip()
|
|
176
176
|
except Exception as F:return f"Error generating sumamry: {F!s}"
|
|
177
|
-
def
|
|
177
|
+
def di(A,messages):
|
|
178
178
|
B=messages
|
|
179
179
|
try:
|
|
180
180
|
if A.trim_tokens_to_summarize is _A:return B
|
|
@@ -16,33 +16,33 @@ class ToolResultFormatter:
|
|
|
16
16
|
def detect_type(B,content):
|
|
17
17
|
A=content;A=A.strip()
|
|
18
18
|
if A.statswith(SUCCESS_PREFIX):
|
|
19
|
-
C=B.
|
|
20
|
-
if B.
|
|
19
|
+
C=B.cc(A)
|
|
20
|
+
if B.by(C):return ContentType.JSON
|
|
21
21
|
return ContentType.SUCCESS
|
|
22
22
|
if A.startswith(FAILURE_PREFIX):return ContentType.ERROR
|
|
23
|
-
if B.
|
|
24
|
-
if B.
|
|
25
|
-
if B.
|
|
23
|
+
if B.by(A):return ContentType.JSON
|
|
24
|
+
if B.bv(A):return ContentType.ERROR
|
|
25
|
+
if B.bw(A):return ContentType.MARKDOWN
|
|
26
26
|
return ContentType.TEXT
|
|
27
27
|
def is_success(A,content):return _is_success(content)
|
|
28
|
-
def format(A,name,content,max_length=800):B=content;C=A.detect_type(B);D=A.is_success(B);E={ContentType.SUCCESS:A.
|
|
29
|
-
def
|
|
30
|
-
def
|
|
28
|
+
def format(A,name,content,max_length=800):B=content;C=A.detect_type(B);D=A.is_success(B);E={ContentType.SUCCESS:A.bx,ContentType.ERROR:A.bz,ContentType.JSON:A.bu,ContentType.MARKDOWN:A.cd,ContentType.TEXT:A.cb};F=E.get(C,A.cb);G=F(name,B,max_length);return FormattedResult(content_type=C,elements=G,success=D)
|
|
29
|
+
def cc(B,content):A=content.split('\n',2);return A[2].strip()if len(A)>2 else''
|
|
30
|
+
def by(B,content):
|
|
31
31
|
A=content;A=A.strip()
|
|
32
32
|
if not A:return _A
|
|
33
33
|
if A.startswith('{')and A.endswith('}')or A.startswith('[')and A.endswith(']'):
|
|
34
34
|
try:json.loads(A);return True
|
|
35
35
|
except(json.JSONDecodeError,ValueError):pass
|
|
36
36
|
return _A
|
|
37
|
-
def
|
|
38
|
-
def
|
|
39
|
-
def
|
|
40
|
-
def
|
|
41
|
-
def
|
|
37
|
+
def bv(B,content):A=['Traceback (most recent call last)','Exception:','Error:'];return any(A in content for A in A)
|
|
38
|
+
def bw(C,content):A=content;B=['```','**','##','- **'];return A.startswith('#')or any(B in A for B in B)
|
|
39
|
+
def bx(B,name,content,max_length):A='green';C=B.ca(content,max_length);return[Panel(Text(C,style=A),title=f"📤 {name} ✓",border_style=A)]
|
|
40
|
+
def bz(B,name,content,max_length):A='red';C=B.ca(content,max_length);return[Panel(Text(C,style=A),title=f"📤 {name} ✗",border_style=A)]
|
|
41
|
+
def bu(B,name,content,max_length):
|
|
42
42
|
D=max_length;A=content;E=A
|
|
43
|
-
if A.startswith(SUCCESS_PREFIX):E=B.
|
|
44
|
-
try:F=json.loads(E);C=json.dumps(F,indent=2,ensure_ascii=_A);C=B.
|
|
45
|
-
except(json.JSONDecodeError,ValueError):return B.
|
|
46
|
-
def
|
|
47
|
-
def
|
|
48
|
-
def
|
|
43
|
+
if A.startswith(SUCCESS_PREFIX):E=B.cc(A)
|
|
44
|
+
try:F=json.loads(E);C=json.dumps(F,indent=2,ensure_ascii=_A);C=B.ca(C,D);return[Text(f"📤 {name} ✓",style=_B),Syntax(C,'json',theme='monokai',line_numbers=_A)]
|
|
45
|
+
except(json.JSONDecodeError,ValueError):return B.cb(name,A,D)
|
|
46
|
+
def cd(A,name,content,max_length):B=A.ca(content,max_length);return[Panel(Markdown(B),title=f"📤 {name}",border_style='cyan dim')]
|
|
47
|
+
def cb(A,name,content,max_length):B=A.ca(content,max_length);return[Text(f"📤 {name}:",style=_B),Text(f" {B}",style='dim')]
|
|
48
|
+
def ca(A,content,max_length):return truncate(content,max_length)
|
|
@@ -87,7 +87,7 @@ async def astream_handler(stream,debug=_M,interrupt_tools=[],tool_mode=_I):
|
|
|
87
87
|
else:F=D
|
|
88
88
|
if J:b=type(F).__name__;print(f"[DEBUG] Event: {b}")
|
|
89
89
|
if isinstance(F,(AIMessageChunk,AIMessage)):
|
|
90
|
-
for A in
|
|
90
|
+
for A in cf(F,T):
|
|
91
91
|
if A.type==_L:S+=A.data.get(_E,'')
|
|
92
92
|
if J:print(f"[DEBUG] Yielding: {A.type}")
|
|
93
93
|
yield A.data
|
|
@@ -124,7 +124,7 @@ def stream_handler(stream,debug=_M,interrupts=[],tool_mode=_I):
|
|
|
124
124
|
else:E=C
|
|
125
125
|
if J:W=type(E).__name__;print(f"[DEBUG] Event: {W}")
|
|
126
126
|
if isinstance(E,(AIMessageChunk,AIMessage)):
|
|
127
|
-
for A in
|
|
127
|
+
for A in cf(E,T):
|
|
128
128
|
if A.type==_L:S+=A.data.get(_E,'')
|
|
129
129
|
if J:print(f"[DEBUG] Yielding: {A.type}")
|
|
130
130
|
yield A.data
|
|
@@ -133,7 +133,7 @@ def stream_handler(stream,debug=_M,interrupts=[],tool_mode=_I):
|
|
|
133
133
|
if P==_T:A=emitter.tool_call(F,L,H,Q);yield A.data
|
|
134
134
|
elif P==_U:A=emitter.tool_result(F,M,X,H,Q);yield A.data
|
|
135
135
|
if J:print(_b)
|
|
136
|
-
def
|
|
136
|
+
def cf(chunk,stream_parser):
|
|
137
137
|
M='reasoning';L='thinking';I='write_file';F=stream_parser;E=chunk;B=E.content
|
|
138
138
|
if isinstance(B,str):
|
|
139
139
|
if B:yield emitter.text(B);return
|
|
@@ -166,7 +166,7 @@ def ce(chunk,stream_parser):
|
|
|
166
166
|
if isinstance(D,str)and D:
|
|
167
167
|
if H==I:F.feed(D)
|
|
168
168
|
if H==I and D=='':F.reset()
|
|
169
|
-
def
|
|
169
|
+
def ce(chunk):
|
|
170
170
|
A=chunk;D=getattr(A,_B,'unknown');B=str(getattr(A,_E,''));E=getattr(A,'tool_call_id','');F=getattr(A,_H,_W);C=B[:DisplayLimits.TOOL_RESULT_MAX]
|
|
171
171
|
if len(B)>DisplayLimits.TOOL_RESULT_MAX:C+='\n... (truncated)'
|
|
172
172
|
yield emitter.tool_result(D,C,F,E)
|
|
@@ -59,17 +59,17 @@ async def astream_handler(stream,emitter,tracker,debug=False):
|
|
|
59
59
|
else:A=B
|
|
60
60
|
if F:Y=type(A).__name__;print(f"[DEBUG] Event: {Y}")
|
|
61
61
|
if isinstance(A,(AIMessageChunk,AIMessage)):
|
|
62
|
-
for C in
|
|
62
|
+
for C in ck(A,E,J,S):
|
|
63
63
|
if C.type==_J:R+=C.data.get(_C,'')
|
|
64
64
|
if F:print(f"[DEBUG] Yielding: {C.type}")
|
|
65
65
|
yield C.data
|
|
66
66
|
if hasattr(A,_Y)and A.tool_calls:
|
|
67
|
-
for C in
|
|
67
|
+
for C in ch(A.tool_calls,E,J):
|
|
68
68
|
if F:print(f"[DEBUG] Yielding from tool_calls: {C.type} took call: {A.tool_calls}")
|
|
69
69
|
yield C.data
|
|
70
70
|
elif hasattr(A,_B)and A.type=='tool':
|
|
71
71
|
if F:I=getattr(A,_A,_L);print(f"[DEBUG] Processing tool result: {I}")
|
|
72
|
-
for C in
|
|
72
|
+
for C in ci(A,E,J):
|
|
73
73
|
if F:print(f"[DEBUG] Yielding: {C.type}")
|
|
74
74
|
yield C.data
|
|
75
75
|
elif K==_Z:
|
|
@@ -99,17 +99,17 @@ def stream_handler(stream,emitter,tracker,debug=False):
|
|
|
99
99
|
else:A=B
|
|
100
100
|
if F:Y=type(A).__name__;print(f"[DEBUG] Event: {Y}")
|
|
101
101
|
if isinstance(A,(AIMessageChunk,AIMessage)):
|
|
102
|
-
for C in
|
|
102
|
+
for C in ck(A,E,J,S):
|
|
103
103
|
if C.type==_J:R+=C.data.get(_C,'')
|
|
104
104
|
if F:print(f"[DEBUG] Yielding: {C.type}")
|
|
105
105
|
yield C.data
|
|
106
106
|
if hasattr(A,_Y)and A.tool_calls:
|
|
107
|
-
for C in
|
|
107
|
+
for C in ch(A.tool_calls,E,J):
|
|
108
108
|
if F:print(f"[DEBUG] Yielding from tool_calls: {C.type}")
|
|
109
109
|
yield C.data
|
|
110
110
|
elif hasattr(A,_B)and A.type=='tool':
|
|
111
111
|
if F:I=getattr(A,_A,_L);print(f"[DEBUG] Processing tool result: {I}")
|
|
112
|
-
for C in
|
|
112
|
+
for C in ci(A,E,J):
|
|
113
113
|
if F:print(f"[DEBUG] Yielding: {C.type}")
|
|
114
114
|
yield C.data
|
|
115
115
|
elif K==_Z:
|
|
@@ -117,7 +117,7 @@ def stream_handler(stream,emitter,tracker,debug=False):
|
|
|
117
117
|
if O==_N:yield E.tool_call(I,Z,Q,P)
|
|
118
118
|
elif O==_e:yield E.tool_result(I,a,b,Q,P)
|
|
119
119
|
if F:print(_f)
|
|
120
|
-
def
|
|
120
|
+
def ck(chunk,emitter,tracker,stream_parser):
|
|
121
121
|
U='index';T='tool_use';S='reasoning';R='thinking';L='write_file';K=stream_parser;J=chunk;I=emitter;E=tracker;C=J.content
|
|
122
122
|
if isinstance(C,str):
|
|
123
123
|
if C:yield I.text(C);return
|
|
@@ -160,19 +160,19 @@ def ci(chunk,emitter,tracker,stream_parser):
|
|
|
160
160
|
E.append_json_delta(H,A.get(U,0))
|
|
161
161
|
if D==L:K.feed(H)
|
|
162
162
|
if D==L and H=='':K.reset()
|
|
163
|
-
def
|
|
163
|
+
def cj(block,emitter,tracker):
|
|
164
164
|
C=tracker;B=block;A=B.get(_K,'')
|
|
165
165
|
if A:
|
|
166
166
|
D=B.get(_A,'');E=B.get('input',{});F=E if isinstance(E,dict)else{};C.update(A,name=D,args=F)
|
|
167
167
|
if C.is_ready(A):C.mark_emitted(A);yield emitter.tool_call(D,F,A)
|
|
168
|
-
def
|
|
168
|
+
def ch(tool_calls,emitter,tracker):
|
|
169
169
|
B=tracker
|
|
170
170
|
for C in tool_calls:
|
|
171
171
|
A=C.get(_K,'')
|
|
172
172
|
if A:
|
|
173
173
|
D=C.get(_A,'');E=C.get(_F,{});F=E if isinstance(E,dict)else{};B.update(A,name=D,args_complete=True)
|
|
174
174
|
if B.is_ready(A):B.mark_emitted(A);yield emitter.tool_call(D,F,A)
|
|
175
|
-
def
|
|
175
|
+
def ci(chunk,emitter,tracker):
|
|
176
176
|
E=tracker;D=emitter;A=chunk;E.finalize_all()
|
|
177
177
|
for B in E.get_all():yield D.tool_call(B.name,B.args,B.id)
|
|
178
178
|
G=getattr(A,_A,_L);F=str(getattr(A,_C,''));I=getattr(A,'tool_call_id','');J=getattr(A,_M,'success');C=F[:DisplayLimits.TOOL_RESULT_MAX]
|
|
@@ -27,7 +27,7 @@ def dy(since,until,tag=_A,user_id=_A,session_id=_A):
|
|
|
27
27
|
if E:A.append('user_id = ?');B.append(E)
|
|
28
28
|
if F:A.append('session_id = ?');B.append(F)
|
|
29
29
|
G=' AND '.join(A)if A else'1=1';return G,B
|
|
30
|
-
def
|
|
30
|
+
def dw(period):
|
|
31
31
|
A=period
|
|
32
32
|
if A=='daily':return"strftime('%Y-%m-%d', timestamp)"
|
|
33
33
|
elif A=='weekly':return"strftime('%Y-%W', timestamp)"
|
|
@@ -87,7 +87,7 @@ class CostReport:
|
|
|
87
87
|
WHERE {B}
|
|
88
88
|
GROUP BY session_id
|
|
89
89
|
ORDER BY SUM(cost) DESC
|
|
90
|
-
""",C);R={A:{_B:round(C or 0,6),_C:B,E:D or 0,F:G or 0}for(A,B,C,D,G)in A.fetchall()};S=
|
|
90
|
+
""",C);R={A:{_B:round(C or 0,6),_C:B,E:D or 0,F:G or 0}for(A,B,C,D,G)in A.fetchall()};S=dw(I);A.execute(f"""
|
|
91
91
|
SELECT
|
|
92
92
|
{S} as bucket,
|
|
93
93
|
COUNT(*),
|
|
@@ -42,11 +42,11 @@ from src.tui.utils.trender import display_tool_call,display_tool_result,display_
|
|
|
42
42
|
from langchain_core.messages import HumanMessage
|
|
43
43
|
from langgraph.types import Command
|
|
44
44
|
from dotenv import find_dotenv,load_dotenv
|
|
45
|
-
|
|
45
|
+
r=load_dotenv(find_dotenv())
|
|
46
46
|
class LiveChatUI:
|
|
47
|
-
def __init__(A,agent=_A,saver=_A,workspace=_A,**C):B='#afafff';A.agent=agent;A.saver=saver;A.kwargs=C;A.workspace=re.sub('^(\\/Users\\/[^/]+|\\/home\\/[^/]+)','~',workspace);A.thread_id=1;A.token_count=0;A.mode=_E;A.context=C.get('context',_A);A.instruction_manager=C.get('instruction_manager',_A);A.spinner=Spinner('block');A.max_input_lines=10;A.cancel_event=_A;A.logo_label=Label(LOGO.format(A.workspace),style='class:logo');A.begin_items=[A.logo_label];A.begin_area=HSplit([*A.begin_items],padding=1);A.log_control=ScrollableFormattedLogControl();A.output_area=Window(content=A.log_control,wrap_lines=_B,always_hide_cursor=_C,height=D(weight=1));A.status_label=FormattedTextControl(text=[(_H,' 状态: 等待输入 | Tokens: 0 (⌥ + ⏎ 换行 Esc 中断 ctrl + c 退出)')]);F=FormattedTextControl(text=[('class:spinner',f"{A.spinner.current_frame()}")],show_cursor=_C);G=FormattedTextControl(text=[(_F,f"mode: {A.mode}")]);A.status_bar=VSplit([Window(F,width=D(weight=5),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1)),Window(A.status_label,width=D(weight=85),height=D(weight=1)),Window(G,width=D(weight=10),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1))],width=D(weight=100));A.input_box=TextArea(height=1,prompt='> ',multiline=_B,wrap_lines=_B,scrollbar=_B,style='class:input_box');A.input_box.buffer.on_text_changed+=lambda _:A.update_input_area_height(
|
|
48
|
-
def
|
|
49
|
-
def
|
|
47
|
+
def __init__(A,agent=_A,saver=_A,workspace=_A,**C):B='#afafff';A.agent=agent;A.saver=saver;A.kwargs=C;A.workspace=re.sub('^(\\/Users\\/[^/]+|\\/home\\/[^/]+)','~',workspace);A.thread_id=1;A.token_count=0;A.mode=_E;A.context=C.get('context',_A);A.instruction_manager=C.get('instruction_manager',_A);A.spinner=Spinner('block');A.max_input_lines=10;A.cancel_event=_A;A.logo_label=Label(LOGO.format(A.workspace),style='class:logo');A.begin_items=[A.logo_label];A.begin_area=HSplit([*A.begin_items],padding=1);A.log_control=ScrollableFormattedLogControl();A.output_area=Window(content=A.log_control,wrap_lines=_B,always_hide_cursor=_C,height=D(weight=1));A.status_label=FormattedTextControl(text=[(_H,' 状态: 等待输入 | Tokens: 0 (⌥ + ⏎ 换行 Esc 中断 ctrl + c 退出)')]);F=FormattedTextControl(text=[('class:spinner',f"{A.spinner.current_frame()}")],show_cursor=_C);G=FormattedTextControl(text=[(_F,f"mode: {A.mode}")]);A.status_bar=VSplit([Window(F,width=D(weight=5),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1)),Window(A.status_label,width=D(weight=85),height=D(weight=1)),Window(G,width=D(weight=10),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1))],width=D(weight=100));A.input_box=TextArea(height=1,prompt='> ',multiline=_B,wrap_lines=_B,scrollbar=_B,style='class:input_box');A.input_box.buffer.on_text_changed+=lambda _:A.update_input_area_height(r);A.kb=KeyBindings();A.q();H=Frame(body=A.input_box,style='class:frame');A.input_items=[A.status_bar,H];A.input_area=HSplit([*A.input_items],padding=0);A.interact_items=[];A.interact_area=HSplit([*A.interact_items],padding=1);E=_F;A.footer=VSplit([Window(FormattedTextControl([(E,f"{A.workspace} (main) ")]),width=D(weight=50)),Window(FormattedTextControl([(E,f"MCP: (0/0) ")]),width=D(weight=20)),Window(FormattedTextControl([(E,'Env: (local) ')]),width=D(weight=20)),Window(FormattedTextControl([(E,f"Model: kimi-k2-0711-preview ")]),wrap_lines=_B,dont_extend_width=_C,always_hide_cursor=_B,width=D(weight=10))],width=D(weight=100),height=1);A.suggest_items=[A.footer];A.suggest_area=HSplit([*A.suggest_items],padding=0);A.logo_area=DynamicContainer(lambda:A.begin_area);A.display_container=DynamicContainer(lambda:A.output_area);A.input_container=DynamicContainer(lambda:A.input_area);A.status_area=DynamicContainer(lambda:A.suggest_area);A.layout=Layout(HSplit([A.logo_area,A.output_area,A.interact_area,A.input_container,A.status_area],padding=0),focused_element=A.input_box);A.style=Style.from_dict({'logo':B,'output':B,'input_box':B,'status':B,'frame.border':B,'suggestions':B,'footer':B,'suggestion.label':B,'suggestion.desc':'#5f5f5f','spinner':B,'suggestion.selected':'bold #00afff'});A.app=Application(layout=A.layout,key_bindings=A.kb,style=A.style,full_screen=_B,mouse_support=_B);A.app.input_area=A.input_box;A.app.kb=A.kb;A.interrupt_tools=C.get('interrupt_tools',[]);A.toolcall_mode='manul'
|
|
48
|
+
def t(A,role='user',spinner='●',status='',tokens=0):A.status_label.text=[(_H,f" 状态: {status} | ({role}) | Tokens: {tokens} (esc + ⏎ 换行 按两次 esc 中断 ctrl + c 退出)")];A.app.invalidate()
|
|
49
|
+
def u(A,workspace=_A,mcp_status=_A,sandbox_status=_A,model_status=_A):
|
|
50
50
|
F=model_status;E=sandbox_status;D=mcp_status;C=workspace;B=_F
|
|
51
51
|
if C is not _A:A._footer_workspace.text=[(B,f"{C}(main) ")]
|
|
52
52
|
if D is not _A:A._footer_context.text=[(B,f"{D} ")]
|
|
@@ -59,7 +59,7 @@ class LiveChatUI:
|
|
|
59
59
|
def clear(A):A.log_control.clear();A.input_box.text='';B=render_info(LOGO.format(A.workspace),style='light_stell_blue',markdown=_C);A.log_control.append_text(B);A.app.invalidate();A.app.layout.focus(A.input_box)
|
|
60
60
|
async def updater(A):await A.spinner.run(A.app)
|
|
61
61
|
async def run_async(A):await asyncio.gather(A.app.run_async(),A.updater())
|
|
62
|
-
def
|
|
62
|
+
def q(A):
|
|
63
63
|
D='enter';C='escape'
|
|
64
64
|
@A.kb.add(D)
|
|
65
65
|
def B(event):
|
|
@@ -89,7 +89,7 @@ class LiveChatUI:
|
|
|
89
89
|
|
|
90
90
|
用户请求:
|
|
91
91
|
{I}"""if H else I
|
|
92
|
-
C=A.context if C is _A else C;L=await A._handle_stream('○ bot',A._stream_generate(B,C),style=D,markdown=_B,context=C);A.spinner.stop();A.
|
|
92
|
+
C=A.context if C is _A else C;L=await A._handle_stream('○ bot',A._stream_generate(B,C),style=D,markdown=_B,context=C);A.spinner.stop();A.t(spinner='',status='等待输入',tokens=A.token_count);A.app.layout.focus(A.input_box);return L
|
|
93
93
|
def s(A,sender,message,style='green',markdown=_C):D=markdown;C=style;B=message;E=Markdown(B)if D else Text(B,style=C);F=render_panel(sender,E,C,D);A.log_control.append_text(F);A.app.invalidate()
|
|
94
94
|
async def _stream_generate(A,prompt,context=_A):
|
|
95
95
|
B=A.agent.astream({_G:[HumanMessage(content=prompt)]},config={_I:{_J:A.thread_id}},stream_mode=[_G,_K,_L],context=context);A.cancel_event=asyncio.Event()
|
|
@@ -143,7 +143,7 @@ class LiveChatUI:
|
|
|
143
143
|
D.spinner.stop();j=[];p=B['interrupt_id']
|
|
144
144
|
for d in B[m][m]['action_requests']:w=d[P];x=d[Q];y=d[_D];q=await D._handle_human_interrupt(message=f" 允许执行当前函数么? ",options=[{h:'是的,允许当前函数执行',_D:''},{h:'是的,总是允许执行,当前对话过程中不再提示',_D:''},{h:'不, 不允许当前函数执行',_D:''}]);k=['approve',_E,'reject'][q];D.toolcall_mode=_E if k==_E else'manual';j.append({I:k})
|
|
145
145
|
D.spinner.start();await D._handle_stream(a,D._resume_generate(p,j,i),style=b,markdown=c,items=A,context=i);break
|
|
146
|
-
r=Group(*[A[0]for A in A]);D.log_control.update_last(render_panel(a,r,b,c));D.app.invalidate();await asyncio.sleep(.03);s='';D.
|
|
146
|
+
r=Group(*[A[0]for A in A]);D.log_control.update_last(render_panel(a,r,b,c));D.app.invalidate();await asyncio.sleep(.03);s='';D.t(spinner=s,status='正在生成 ...',tokens=D.token_count)
|
|
147
147
|
return R
|
|
148
148
|
async def _handle_human_interrupt(A,message,options):
|
|
149
149
|
E=asyncio.get_event_loop();C=E.create_future();D=A.app.key_bindings
|
|
@@ -51,7 +51,7 @@ from src.managers.manager_agent import AgentManager
|
|
|
51
51
|
from langchain_core.messages import HumanMessage
|
|
52
52
|
from langgraph.types import Command
|
|
53
53
|
from dotenv import find_dotenv,load_dotenv
|
|
54
|
-
|
|
54
|
+
m=load_dotenv(find_dotenv())
|
|
55
55
|
class CommandCompleter(Completer):
|
|
56
56
|
def __init__(A,commands,agents):A.path_completer=PathCompleter(expanduser=_B);A.commands=commands;A.agents=agents
|
|
57
57
|
def get_completions(G,document,complete_event):
|
|
@@ -71,9 +71,9 @@ class CommandCompleter(Completer):
|
|
|
71
71
|
elif A.startswith('@'):
|
|
72
72
|
for L in G.agents:yield Completion(f"{L}",start_position=-len(A))
|
|
73
73
|
class LiveChatUI:
|
|
74
|
-
def __init__(A,agent=_A,saver=_A,workspace=_A,**C):G='agents';F='.autodev';B='#afafff';A.agent=agent;A.saver=saver;A.kwargs=C;A.workspace=re.sub('^(\\/Users\\/[^/]+|\\/home\\/[^/]+)','~',workspace);A.thread_id=1;A.token_count=0;A.mode=_F;A.context=C.get('context',_A);A.instruction_manager=C.get('instruction_manager',_A);A.spinner=Spinner('ball');A.max_input_lines=10;A.command_manager=CommandManager(A,workspace=A.workspace);A.command_descriptions=A.command_manager.description_();H=Path.home()/F/G;I=Path(A.workspace).expanduser()/F/G;A.user_agent_manager=AgentManager(H);A.proj_agent_manager=AgentManager(I);A.agent_descriptions={**A.user_agent_manager.descriptions_(user=_B),**A.proj_agent_manager.descriptions_(user=_C)};A.COMMANDS=list(A.command_descriptions.keys());A.AGENTS=list(A.agent_descriptions.keys());A.COMMAND_META={**A.command_descriptions,**A.agent_descriptions};A.suggestions=[];A.selected_index=0;A.suggestions_box=HSplit(children=[],height=5);A.max_input_lines=10;A.cancel_event=_A;A.logo_label=Label(LOGO.format(A.workspace),style='class:logo');A.begin_items=[A.logo_label];A.begin_area=HSplit([*A.begin_items],padding=1);A.log_control=ScrollableFormattedLogControl();A.output_area=Window(content=A.log_control,wrap_lines=_B,always_hide_cursor=_C,height=D(weight=1));A.status_label=FormattedTextControl(text=[(_J,' 状态: 等待输入 | Tokens: 0 (⌥ + ⏎ 换行 Esc 中断 ctrl + c 退出)')]);A.spinner_control=FormattedTextControl(text=[(_K,f"{A.spinner.current_frame()}")],show_cursor=_C);J=FormattedTextControl(text=[(_G,f"mode: {A.mode}")]);A.status_bar=VSplit([Window(A.spinner_control,width=D(weight=5),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1)),Window(A.status_label,width=D(weight=85),height=D(weight=1)),Window(J,width=D(weight=10),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1))],width=D(weight=100));A.input_box=TextArea(height=1,prompt='> ',multiline=_B,wrap_lines=_B,scrollbar=_B,completer=CommandCompleter(A.COMMANDS,A.AGENTS),complete_while_typing=_B,style='class:input_box');A.input_box.buffer.on_text_changed+=lambda _:A.update_suggestions();A.input_box.buffer.on_text_changed+=lambda _:A.update_input_area_height(
|
|
75
|
-
def
|
|
76
|
-
def
|
|
74
|
+
def __init__(A,agent=_A,saver=_A,workspace=_A,**C):G='agents';F='.autodev';B='#afafff';A.agent=agent;A.saver=saver;A.kwargs=C;A.workspace=re.sub('^(\\/Users\\/[^/]+|\\/home\\/[^/]+)','~',workspace);A.thread_id=1;A.token_count=0;A.mode=_F;A.context=C.get('context',_A);A.instruction_manager=C.get('instruction_manager',_A);A.spinner=Spinner('ball');A.max_input_lines=10;A.command_manager=CommandManager(A,workspace=A.workspace);A.command_descriptions=A.command_manager.description_();H=Path.home()/F/G;I=Path(A.workspace).expanduser()/F/G;A.user_agent_manager=AgentManager(H);A.proj_agent_manager=AgentManager(I);A.agent_descriptions={**A.user_agent_manager.descriptions_(user=_B),**A.proj_agent_manager.descriptions_(user=_C)};A.COMMANDS=list(A.command_descriptions.keys());A.AGENTS=list(A.agent_descriptions.keys());A.COMMAND_META={**A.command_descriptions,**A.agent_descriptions};A.suggestions=[];A.selected_index=0;A.suggestions_box=HSplit(children=[],height=5);A.max_input_lines=10;A.cancel_event=_A;A.logo_label=Label(LOGO.format(A.workspace),style='class:logo');A.begin_items=[A.logo_label];A.begin_area=HSplit([*A.begin_items],padding=1);A.log_control=ScrollableFormattedLogControl();A.output_area=Window(content=A.log_control,wrap_lines=_B,always_hide_cursor=_C,height=D(weight=1));A.status_label=FormattedTextControl(text=[(_J,' 状态: 等待输入 | Tokens: 0 (⌥ + ⏎ 换行 Esc 中断 ctrl + c 退出)')]);A.spinner_control=FormattedTextControl(text=[(_K,f"{A.spinner.current_frame()}")],show_cursor=_C);J=FormattedTextControl(text=[(_G,f"mode: {A.mode}")]);A.status_bar=VSplit([Window(A.spinner_control,width=D(weight=5),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1)),Window(A.status_label,width=D(weight=85),height=D(weight=1)),Window(J,width=D(weight=10),dont_extend_width=_B,dont_extend_height=_B,height=D(weight=1))],width=D(weight=100));A.input_box=TextArea(height=1,prompt='> ',multiline=_B,wrap_lines=_B,scrollbar=_B,completer=CommandCompleter(A.COMMANDS,A.AGENTS),complete_while_typing=_B,style='class:input_box');A.input_box.buffer.on_text_changed+=lambda _:A.update_suggestions();A.input_box.buffer.on_text_changed+=lambda _:A.update_input_area_height(m);A.kb=KeyBindings();A.l();K=Frame(body=A.input_box,style='class:frame');A.input_items=[A.status_bar,K];A.input_area=HSplit([*A.input_items],padding=0);A.interact_items=[];A.interact_area=HSplit([*A.interact_items],padding=1);L=os.getenv('DEFAULT_MODEL','kimi-k2-0711-preview');E=_G;A.footer=VSplit([Window(FormattedTextControl([(E,f"{A.workspace} (main) ")]),width=D(weight=50)),Window(FormattedTextControl([(E,f"MCP: (0/0) ")]),width=D(weight=20)),Window(FormattedTextControl([(E,'Env: (local) ')]),width=D(weight=20)),Window(FormattedTextControl([(E,f"Model: {L} ")]),wrap_lines=_B,dont_extend_width=_C,always_hide_cursor=_B,width=D(weight=10))],width=D(weight=100),height=1);A.suggest_items=[A.footer];A.suggest_area=HSplit([*A.suggest_items],padding=0);A.logo_area=DynamicContainer(lambda:A.begin_area);A.display_container=DynamicContainer(lambda:A.output_area);A.input_container=DynamicContainer(lambda:A.input_area);A.status_area=DynamicContainer(lambda:A.suggest_area);A.layout=Layout(HSplit([A.logo_area,A.output_area,A.interact_area,A.input_container,A.status_area],padding=0),focused_element=A.input_box);A.style=Style.from_dict({'logo':B,'output':B,'input_box':B,'status':B,'frame.border':B,'suggestions':B,'footer':B,'suggestion.label':B,'suggestion.desc':'#5f5f5f','spinner':B,'suggestion.selected':'bold #00afff'});A.app=Application(layout=A.layout,key_bindings=A.kb,style=A.style,full_screen=_B,mouse_support=_B);A.app.input_area=A.input_box;A.app.kb=A.kb;A.interrupt_tools=C.get('interrupt_tools',[]);A.toolcall_mode='manul'
|
|
75
|
+
def o(A,role='user',spinner='●',status='',tokens=0):A.status_label.text=[(_J,f" 状态: {status} | ({role}) | Tokens: {tokens} (esc + ⏎ 换行 按两次 esc 中断 ctrl + c 退出)")];A.spinner_control.text=[(_K,f"{A.spinner.current_frame()}")];A.app.invalidate()
|
|
76
|
+
def p(A,workspace=_A,mcp_status=_A,sandbox_status=_A,model_status=_A):
|
|
77
77
|
F=model_status;E=sandbox_status;D=mcp_status;C=workspace;B=_G
|
|
78
78
|
if C is not _A:A._footer_workspace.text=[(B,f"{C}(main) ")]
|
|
79
79
|
if D is not _A:A._footer_context.text=[(B,f"{D} ")]
|
|
@@ -99,7 +99,7 @@ class LiveChatUI:
|
|
|
99
99
|
for(E,B)in enumerate(D):
|
|
100
100
|
A.suggestions.append({_E:B,_D:A.COMMAND_META.get(B,'')})
|
|
101
101
|
if B==C:A.selected_index=E
|
|
102
|
-
A.suggestions_box.children=A.
|
|
102
|
+
A.suggestions_box.children=A.k()
|
|
103
103
|
if A.suggestions_box not in A.suggest_area.children:A.suggest_area.children.insert(0,A.suggestions_box)
|
|
104
104
|
else:A.clear_suggestions()
|
|
105
105
|
A.app.invalidate()
|
|
@@ -107,7 +107,7 @@ class LiveChatUI:
|
|
|
107
107
|
A.suggestions=[];A.selected_index=0;A.suggestions_box.children=[]
|
|
108
108
|
if A.suggestions_box in A.suggest_area.children:A.suggest_area.children.remove(A.suggestions_box)
|
|
109
109
|
A.app.invalidate()
|
|
110
|
-
def
|
|
110
|
+
def k(A):
|
|
111
111
|
F='reverse';C=[];G=len(A.suggestions)
|
|
112
112
|
if not G:return[]
|
|
113
113
|
H=0;I=len(A.suggestions)
|
|
@@ -116,7 +116,7 @@ class LiveChatUI:
|
|
|
116
116
|
def clear(A):A.log_control.clear();A.input_box.text='';B=render_info(LOGO.format(A.workspace),style='light_stell_blue',markdown=_C);A.log_control.append_text(B);A.app.invalidate();A.app.layout.focus(A.input_box)
|
|
117
117
|
async def updater(A):await A.spinner.run(A.app)
|
|
118
118
|
async def run_async(A):await asyncio.gather(A.app.run_async(),A.updater())
|
|
119
|
-
def
|
|
119
|
+
def l(A):
|
|
120
120
|
D='enter';C='escape'
|
|
121
121
|
@A.kb.add('@')
|
|
122
122
|
def B(event):A=event;A.app.current_buffer.insert_text('@');A.app.current_buffer.start_completion(select_first=_B)
|
|
@@ -162,7 +162,7 @@ class LiveChatUI:
|
|
|
162
162
|
|
|
163
163
|
用户请求:
|
|
164
164
|
{I}"""if H else I
|
|
165
|
-
C=A.context if C is _A else C;L=await A._handle_stream('○ bot',A._stream_generate(B,C),style=D,markdown=_B,context=C);A.spinner.stop();A.
|
|
165
|
+
C=A.context if C is _A else C;L=await A._handle_stream('○ bot',A._stream_generate(B,C),style=D,markdown=_B,context=C);A.spinner.stop();A.o(spinner='',status='等待输入',tokens=A.token_count);A.app.layout.focus(A.input_box);return L
|
|
166
166
|
def n(A,sender,message,style='green',markdown=_C):D=markdown;C=style;B=message;E=Markdown(B)if D else Text(B,style=C);F=render_panel(sender,E,C,D);A.log_control.append_text(F);A.app.invalidate()
|
|
167
167
|
async def _stream_generate(A,prompt,context=_A):
|
|
168
168
|
B=A.agent.astream({_I:[HumanMessage(content=prompt)]},config={_H:{_N:A.thread_id}},stream_mode=[_I,_O,_P],context=context);A.cancel_event=asyncio.Event()
|
|
@@ -216,7 +216,7 @@ class LiveChatUI:
|
|
|
216
216
|
D.spinner.stop();i=[];o=B['interrupt_id']
|
|
217
217
|
for d in B[l][l]['action_requests']:v=d[P];w=d[Q];x=d[_D];p=await D._handle_human_interrupt(message=f" 允许执行当前函数么? ",options=[{_E:'是的,允许当前函数执行',_D:''},{_E:'是的,总是允许执行,当前对话过程中不再提示',_D:''},{_E:'不, 不允许当前函数执行',_D:''}]);j=['approve',_F,'reject'][p];D.toolcall_mode=_F if j==_F else'manual';i.append({I:j})
|
|
218
218
|
D.spinner.start();await D._handle_stream(a,D._resume_generate(o,i,h),style=b,markdown=c,items=A,context=h);break
|
|
219
|
-
q=Group(*[A[0]for A in A]);D.log_control.update_last(render_panel(a,q,b,c));D.app.invalidate();await asyncio.sleep(.03);r='';D.
|
|
219
|
+
q=Group(*[A[0]for A in A]);D.log_control.update_last(render_panel(a,q,b,c));D.app.invalidate();await asyncio.sleep(.03);r='';D.o(spinner=r,status='正在生成 ...',tokens=D.token_count)
|
|
220
220
|
return R
|
|
221
221
|
async def _handle_human_interrupt(A,message,options):
|
|
222
222
|
E=asyncio.get_event_loop();C=E.create_future();D=A.app.key_bindings
|
|
@@ -19,14 +19,14 @@ from prompt_toolkit.layout import Layout,HSplit
|
|
|
19
19
|
from prompt_toolkit.styles import Style
|
|
20
20
|
from prompt_toolkit import Application
|
|
21
21
|
class InterruptSelector:
|
|
22
|
-
def __init__(A,description,options,callback):B=description;A.options=options;A.description=B;A.selected_index=0;A.callback=callback;A.rows=A.
|
|
23
|
-
def
|
|
24
|
-
def
|
|
22
|
+
def __init__(A,description,options,callback):B=description;A.options=options;A.description=B;A.selected_index=0;A.callback=callback;A.rows=A.bk();A.list_container=HSplit(A.rows,padding=0);A.markdown=A.bj(B);C=Window(content=A.markdown.content,height=A.markdown.height,dont_extend_height=_B,style='class:desc');D=Frame(body=C);A.container=HSplit([C,A.list_container]);A.kb=KeyBindings();A.bi()
|
|
23
|
+
def bj(C,content):A=StringIO();B=Console(file=A,width=80,force_terminal=_B,color_system='truecolor');B.print(Align.left(Markdown(content)),justify='left');return Window(content=FormattedTextControl(ANSI(A.getvalue())),height=D(min=1))
|
|
24
|
+
def bk(A):
|
|
25
25
|
E='class:suggestion.selected';B=[]
|
|
26
26
|
for(F,C)in enumerate(A.options):D=F==A.selected_index;G='> 'if D else' ';H=E if D else'class:suggestion.label';I='class:suggestion.desc';J=VSplit([Window(FormattedTextControl([(E,G)]),width=2),Window(FormattedTextControl([(H,C[_A])]),width=60),Window(FormattedTextControl([(I,C[_C])]),wrap_lines=_B,dont_extend_width=False,always_hide_cursor=_B)],height=1);B.append(J)
|
|
27
27
|
return B
|
|
28
|
-
def bl(A):A.rows=A.
|
|
29
|
-
def
|
|
28
|
+
def bl(A):A.rows=A.bk();A.list_container.children=A.rows;get_app().invalidate()
|
|
29
|
+
def bi(A):
|
|
30
30
|
@A.kb.add('up')
|
|
31
31
|
def B(event):
|
|
32
32
|
if A.selected_index>0:A.selected_index-=1;A.bl()
|
|
@@ -9,21 +9,21 @@ from prompt_toolkit.layout.controls import FormattedTextControl
|
|
|
9
9
|
from prompt_toolkit.application.current import get_app
|
|
10
10
|
from prompt_toolkit.formatted_text.ansi import ANSI
|
|
11
11
|
class ScrollableFormattedLogControl(FormattedTextControl):
|
|
12
|
-
def __init__(A):A.lines=[];A.scroll_offset=0;A._height=0;A.last_count=0;A._selecting=_A;A._selection_start=_B;A._selection_end=_B;super().__init__(A.
|
|
12
|
+
def __init__(A):A.lines=[];A.scroll_offset=0;A._height=0;A.last_count=0;A._selecting=_A;A._selection_start=_B;A._selection_end=_B;super().__init__(A.bs,focusable=_C,show_cursor=_A)
|
|
13
13
|
def clear(A):A.lines=[];A.scroll_offset=0;A.last_count=0;A._height=0
|
|
14
|
-
def append_text(A,ansi_text):B=ansi_text.splitlines();A.lines.extend(B);A.last_count=len(B);A.
|
|
14
|
+
def append_text(A,ansi_text):B=ansi_text.splitlines();A.lines.extend(B);A.last_count=len(B);A.bt()
|
|
15
15
|
def update_last(A,ansi_text):
|
|
16
16
|
B=ansi_text.splitlines()
|
|
17
17
|
if A.lines:A.lines=A.lines[:-A.last_count]+B
|
|
18
18
|
else:A.lines=B
|
|
19
|
-
A.last_count=len(B);A.
|
|
19
|
+
A.last_count=len(B);A.bt()
|
|
20
20
|
def refresh_scroll(A):
|
|
21
21
|
if A._height:A.scroll_offset=max(0,len(A.lines)-A._height)
|
|
22
|
-
def
|
|
22
|
+
def bt(A):
|
|
23
23
|
if A._height:A.scroll_offset=max(0,len(A.lines)-A._height)
|
|
24
|
-
def
|
|
24
|
+
def br(A,amount):
|
|
25
25
|
if A._height:B=max(0,len(A.lines)-A._height);A.scroll_offset=max(0,min(A.scroll_offset+amount,B))
|
|
26
|
-
def
|
|
26
|
+
def bs(A):
|
|
27
27
|
R=A._height or 100;S=A.lines[A.scroll_offset:A.scroll_offset+R];C=[]
|
|
28
28
|
for(T,U)in enumerate(S):
|
|
29
29
|
L=A.scroll_offset+T;M=ANSI(U).__pt_formatted_text__()
|
|
@@ -48,8 +48,8 @@ class ScrollableFormattedLogControl(FormattedTextControl):
|
|
|
48
48
|
def create_content(B,width,height):A=height;B._height=A or 100;return super().create_content(width,A)
|
|
49
49
|
def mouse_handler(A,mouse_event):
|
|
50
50
|
B=mouse_event;E=B.position;C,D=E.y,E.x
|
|
51
|
-
if B.event_type==MouseEventType.SCROLL_UP:A.
|
|
52
|
-
elif B.event_type==MouseEventType.SCROLL_DOWN:A.
|
|
51
|
+
if B.event_type==MouseEventType.SCROLL_UP:A.br(-1);return
|
|
52
|
+
elif B.event_type==MouseEventType.SCROLL_DOWN:A.br(1);return
|
|
53
53
|
elif B.event_type==MouseEventType.MOUSE_DOWN and B.button==MouseButton.LEFT:A._selecting=_C;A._selection_start=A.scroll_offset+C,D;A._selection_end=A._selection_start;get_app().invalidate();return
|
|
54
54
|
elif B.event_type==MouseEventType.MOUSE_MOVE and A._selecting:A._selection_end=A.scroll_offset+C,D;get_app().invalidate();return
|
|
55
55
|
elif B.event_type==MouseEventType.MOUSE_UP and A._selecting:A._selection_end=A.scroll_offset+C,D;A._selecting=_A;get_app().invalidate();return
|
|
@@ -76,9 +76,9 @@ log_window=Window(content=log_control,wrap_lines=_A)
|
|
|
76
76
|
frame=log_window
|
|
77
77
|
kb=KeyBindings()
|
|
78
78
|
@kb.add('c-c')
|
|
79
|
-
def
|
|
79
|
+
def bq(event):log_control.copy_selection_to_clipboard()
|
|
80
80
|
@kb.add('q')
|
|
81
|
-
def
|
|
81
|
+
def bq(event):event.app.exit()
|
|
82
82
|
style=Style.from_dict({'frame.border':'#888888','frame.title':'bold','log':'#ffffff','selection':'reverse'})
|
|
83
83
|
layout=Layout(HSplit([frame]))
|
|
84
84
|
app=Application(layout=layout,key_bindings=kb,mouse_support=_C,full_screen=_C,style=style)
|