mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-05 23:51:25 +08:00
feat: add model name display in AI actions and optimize HTML report
- Add ModelName field to PlanningResult and SubActionResult - Update HTML report with improved layout and model name display - Fix elapsed time setting bug and enhance mobile responsiveness
This commit is contained in:
@@ -1 +1 @@
|
|||||||
v5.0.0-beta-2506081925
|
v5.0.0-beta-2506082208
|
||||||
|
|||||||
@@ -449,16 +449,46 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.header h1 {
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-left h1 {
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header .subtitle {
|
.header-left .subtitle {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-time {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
padding: 12px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.9em;
|
||||||
|
opacity: 0.8;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-value {
|
||||||
|
display: block;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.summary {
|
.summary {
|
||||||
background: white;
|
background: white;
|
||||||
padding: 25px;
|
padding: 25px;
|
||||||
@@ -511,16 +541,83 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
|
|
||||||
.platform-info {
|
.platform-info {
|
||||||
background: #e9ecef;
|
background: #e9ecef;
|
||||||
padding: 15px;
|
padding: 20px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.platform-info h3 {
|
.platform-info h3 {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 15px;
|
||||||
color: #495057;
|
color: #495057;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.platform-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-item {
|
||||||
|
background: white;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-item:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-label {
|
||||||
|
font-size: 1.0em;
|
||||||
|
color: #6c757d;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-value {
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #2c3e50;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls button {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
margin: 0 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls button:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls button:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.step-container {
|
.step-container {
|
||||||
background: white;
|
background: white;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
@@ -643,16 +740,56 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-header:hover {
|
||||||
|
background-color: rgba(0, 123, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-header strong {
|
.action-header strong {
|
||||||
color: #007bff;
|
color: #007bff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-toggle {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #6c757d;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-toggle.rotated {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-toggle.collapsed {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-content.expanded {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.action-params {
|
.action-params {
|
||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
@@ -674,6 +811,22 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-action-content {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-action-left {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-action-right {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.sub-action-header {
|
.sub-action-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -691,13 +844,53 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
}
|
}
|
||||||
|
|
||||||
.thought {
|
.thought {
|
||||||
background: #fff3cd;
|
background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%);
|
||||||
border: 1px solid #ffeaa7;
|
border: 2px solid #2196f3;
|
||||||
border-radius: 6px;
|
border-radius: 12px;
|
||||||
padding: 8px;
|
padding: 15px;
|
||||||
margin: 8px 0;
|
margin: 10px 0;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: #856404;
|
color: #1565c0;
|
||||||
|
font-size: 1.0em;
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.15);
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thought::before {
|
||||||
|
content: "💭";
|
||||||
|
font-size: 1.2em;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 0px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-name-container {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin: 8px 0;
|
||||||
|
font-size: 0.9em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-value {
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
|
background: #e9ecef;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arguments {
|
.arguments {
|
||||||
@@ -711,7 +904,31 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
}
|
}
|
||||||
|
|
||||||
.requests {
|
.requests {
|
||||||
margin-top: 10px;
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.requests-toggle {
|
||||||
|
background: #6c757d;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.requests-toggle:hover {
|
||||||
|
background: #5a6268;
|
||||||
|
}
|
||||||
|
|
||||||
|
.requests-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.requests-content.show {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.request-item {
|
.request-item {
|
||||||
@@ -774,7 +991,24 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sub-action-screenshots, .screenshots-section {
|
.sub-action-screenshots, .screenshots-section {
|
||||||
margin-top: 15px;
|
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||||
|
border: 2px solid #28a745;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-action-screenshots h5, .screenshots-section h4 {
|
||||||
|
color: #155724;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 1.0em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screenshots-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.screenshot-item {
|
.screenshot-item {
|
||||||
@@ -783,6 +1017,13 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screenshot-item:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screenshot-item.small {
|
.screenshot-item.small {
|
||||||
@@ -876,12 +1117,50 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logs-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 8px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-header:hover {
|
||||||
|
background: #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-header h4 {
|
||||||
|
margin: 0;
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-toggle {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #6c757d;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-toggle.collapsed {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
.logs-container {
|
.logs-container {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border: 1px solid #dee2e6;
|
border: 1px solid #dee2e6;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-container.show {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-entry {
|
.log-entry {
|
||||||
@@ -1065,10 +1344,43 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header h1 {
|
.header-content {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-left h1 {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-time {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-grid {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-item {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-label {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-value {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.summary-grid {
|
.summary-grid {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
@@ -1091,12 +1403,38 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controls button {
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-header h4 {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
.request-header {
|
.request-header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-action-content {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screenshots-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.screenshot-image img {
|
.screenshot-image img {
|
||||||
max-height: 250px;
|
max-height: 250px;
|
||||||
}
|
}
|
||||||
@@ -1140,9 +1478,19 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="header-left">
|
||||||
<h1>🚀 HttpRunner Test Report</h1>
|
<h1>🚀 HttpRunner Test Report</h1>
|
||||||
<div class="subtitle">Automated Testing Results</div>
|
<div class="subtitle">Automated Testing Results</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<div class="start-time">
|
||||||
|
<span class="time-label">Start Time:</span>
|
||||||
|
<span class="time-value">{{.Time.StartAt.Format "2006-01-02 15:04:05"}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="summary">
|
<div class="summary">
|
||||||
<h2>📊 Test Summary</h2>
|
<h2>📊 Test Summary</h2>
|
||||||
@@ -1187,16 +1535,26 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
|
|
||||||
<div class="platform-info">
|
<div class="platform-info">
|
||||||
<h3>🔧 Platform Information</h3>
|
<h3>🔧 Platform Information</h3>
|
||||||
<p><strong>HttpRunner Version:</strong> {{.Platform.HttprunnerVersion}}</p>
|
<div class="platform-grid">
|
||||||
<p><strong>Go Version:</strong> {{.Platform.GoVersion}}</p>
|
<div class="platform-item">
|
||||||
<p><strong>Platform:</strong> {{.Platform.Platform}}</p>
|
<div class="platform-label">HttpRunner Version</div>
|
||||||
<p><strong>Start Time:</strong> {{.Time.StartAt.Format "2006-01-02 15:04:05"}}</p>
|
<div class="platform-value">{{.Platform.HttprunnerVersion}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="platform-item">
|
||||||
|
<div class="platform-label">Go Version</div>
|
||||||
|
<div class="platform-value">{{.Platform.GoVersion}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="platform-item">
|
||||||
|
<div class="platform-label">Platform</div>
|
||||||
|
<div class="platform-value">{{.Platform.Platform}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button onclick="expandAll()">Expand All</button>
|
<button id="toggleStepsBtn" onclick="toggleAllSteps()">Collapse All Steps</button>
|
||||||
<button onclick="collapseAll()">Collapse All</button>
|
<button id="toggleActionsBtn" onclick="toggleAllActions()">Expand All Actions</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="test-cases">
|
<div class="test-cases">
|
||||||
@@ -1234,11 +1592,13 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
<h4>Actions</h4>
|
<h4>Actions</h4>
|
||||||
{{range $actionIndex, $action := $step.Actions}}
|
{{range $actionIndex, $action := $step.Actions}}
|
||||||
<div class="action-item">
|
<div class="action-item">
|
||||||
<div class="action-header">
|
<div class="action-header" onclick="toggleAction({{$stepIndex}}, {{$actionIndex}})">
|
||||||
<strong>{{$action.Method}}</strong>
|
<strong>{{$action.Method}}</strong>
|
||||||
<span class="duration">{{formatDuration $action.Elapsed}}</span>
|
<span class="duration">{{formatDuration $action.Elapsed}}</span>
|
||||||
{{if $action.Error}}<span class="error">Error: {{$action.Error}}</span>{{end}}
|
{{if $action.Error}}<span class="error">Error: {{$action.Error}}</span>{{end}}
|
||||||
|
<span class="action-toggle collapsed" id="action-toggle-{{$stepIndex}}-{{$actionIndex}}">▶</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="action-content" id="action-content-{{$stepIndex}}-{{$actionIndex}}">
|
||||||
<div class="action-params">{{$action.Params}}</div>
|
<div class="action-params">{{$action.Params}}</div>
|
||||||
|
|
||||||
{{if $action.SubActions}}
|
{{if $action.SubActions}}
|
||||||
@@ -1250,16 +1610,29 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
<span class="duration">{{formatDuration $subAction.Elapsed}}</span>
|
<span class="duration">{{formatDuration $subAction.Elapsed}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if $subAction.Thought}}
|
<div class="sub-action-content">
|
||||||
<div class="thought">💭 {{$subAction.Thought}}</div>
|
<div class="sub-action-left">
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if $subAction.Arguments}}
|
{{if $subAction.Arguments}}
|
||||||
<div class="arguments">Arguments: {{safeHTML (toJSON $subAction.Arguments)}}</div>
|
<div class="arguments">Arguments: {{safeHTML (toJSON $subAction.Arguments)}}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if $subAction.Thought}}
|
||||||
|
<div class="thought">{{$subAction.Thought}}</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $subAction.ModelName}}
|
||||||
|
<div class="model-name-container">
|
||||||
|
<span class="model-label">🤖 Model:</span>
|
||||||
|
<span class="model-value">{{$subAction.ModelName}}</span>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if $subAction.Requests}}
|
{{if $subAction.Requests}}
|
||||||
<div class="requests">
|
<div class="requests">
|
||||||
|
<button class="requests-toggle" onclick="toggleRequests(this)">
|
||||||
|
📡 Show Requests ({{len $subAction.Requests}})
|
||||||
|
</button>
|
||||||
|
<div class="requests-content">
|
||||||
{{range $request := $subAction.Requests}}
|
{{range $request := $subAction.Requests}}
|
||||||
<div class="request-item">
|
<div class="request-item">
|
||||||
<div class="request-header">
|
<div class="request-header">
|
||||||
@@ -1277,10 +1650,15 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{if $subAction.ScreenResults}}
|
{{if $subAction.ScreenResults}}
|
||||||
|
<div class="sub-action-right">
|
||||||
<div class="sub-action-screenshots">
|
<div class="sub-action-screenshots">
|
||||||
|
<h5>📸 Screenshots</h5>
|
||||||
|
<div class="screenshots-grid">
|
||||||
{{range $screenshot := $subAction.ScreenResults}}
|
{{range $screenshot := $subAction.ScreenResults}}
|
||||||
{{$base64Image := encodeImageBase64 $screenshot.ImagePath}}
|
{{$base64Image := encodeImageBase64 $screenshot.ImagePath}}
|
||||||
{{if $base64Image}}
|
{{if $base64Image}}
|
||||||
@@ -1298,12 +1676,16 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -1355,8 +1737,11 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
{{$stepLogs := getStepLogs $step}}
|
{{$stepLogs := getStepLogs $step}}
|
||||||
{{if $stepLogs}}
|
{{if $stepLogs}}
|
||||||
<div class="logs-section">
|
<div class="logs-section">
|
||||||
<h4>📋 Step Logs</h4>
|
<div class="logs-header" onclick="toggleStepLogs({{$stepIndex}})">
|
||||||
<div class="logs-container">
|
<h4>📋 Step Logs ({{len $stepLogs}})</h4>
|
||||||
|
<span class="logs-toggle collapsed" id="logs-toggle-{{$stepIndex}}">▶</span>
|
||||||
|
</div>
|
||||||
|
<div class="logs-container" id="logs-container-{{$stepIndex}}">
|
||||||
{{range $logEntry := $stepLogs}}
|
{{range $logEntry := $stepLogs}}
|
||||||
<div class="log-entry {{$logEntry.Level}}">
|
<div class="log-entry {{$logEntry.Level}}">
|
||||||
<div class="log-header" {{if $logEntry.Fields}}onclick="toggleLogFields(this)"{{end}}>
|
<div class="log-header" {{if $logEntry.Fields}}onclick="toggleLogFields(this)"{{end}}>
|
||||||
@@ -1419,6 +1804,49 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleStepLogs(stepIndex) {
|
||||||
|
const container = document.getElementById('logs-container-' + stepIndex);
|
||||||
|
const toggle = document.getElementById('logs-toggle-' + stepIndex);
|
||||||
|
|
||||||
|
if (container.classList.contains('show')) {
|
||||||
|
container.classList.remove('show');
|
||||||
|
toggle.classList.add('collapsed');
|
||||||
|
toggle.textContent = '▶';
|
||||||
|
} else {
|
||||||
|
container.classList.add('show');
|
||||||
|
toggle.classList.remove('collapsed');
|
||||||
|
toggle.textContent = '▼';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleRequests(buttonElement) {
|
||||||
|
const requestsDiv = buttonElement.parentElement;
|
||||||
|
const requestsContent = requestsDiv.querySelector('.requests-content');
|
||||||
|
|
||||||
|
if (requestsContent.classList.contains('show')) {
|
||||||
|
requestsContent.classList.remove('show');
|
||||||
|
buttonElement.textContent = buttonElement.textContent.replace('Hide', 'Show');
|
||||||
|
} else {
|
||||||
|
requestsContent.classList.add('show');
|
||||||
|
buttonElement.textContent = buttonElement.textContent.replace('Show', 'Hide');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAction(stepIndex, actionIndex) {
|
||||||
|
const content = document.getElementById('action-content-' + stepIndex + '-' + actionIndex);
|
||||||
|
const toggle = document.getElementById('action-toggle-' + stepIndex + '-' + actionIndex);
|
||||||
|
|
||||||
|
if (content.classList.contains('expanded')) {
|
||||||
|
content.classList.remove('expanded');
|
||||||
|
toggle.classList.add('collapsed');
|
||||||
|
toggle.textContent = '▶';
|
||||||
|
} else {
|
||||||
|
content.classList.add('expanded');
|
||||||
|
toggle.classList.remove('collapsed');
|
||||||
|
toggle.textContent = '▼';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openImageModal(src) {
|
function openImageModal(src) {
|
||||||
const modal = document.getElementById('imageModal');
|
const modal = document.getElementById('imageModal');
|
||||||
const modalImg = document.getElementById('modalImage');
|
const modalImg = document.getElementById('modalImage');
|
||||||
@@ -1438,34 +1866,70 @@ const htmlTemplate = `<!DOCTYPE html>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand all steps
|
// Toggle all steps
|
||||||
function expandAll() {
|
function toggleAllSteps() {
|
||||||
const contents = document.querySelectorAll('.step-content');
|
const contents = document.querySelectorAll('.step-content');
|
||||||
const icons = document.querySelectorAll('.toggle-icon');
|
const icons = document.querySelectorAll('.toggle-icon');
|
||||||
|
const button = document.getElementById('toggleStepsBtn');
|
||||||
|
|
||||||
|
// Check if any step is currently expanded
|
||||||
|
const anyExpanded = Array.from(contents).some(content => content.classList.contains('show'));
|
||||||
|
|
||||||
|
if (anyExpanded) {
|
||||||
|
// Collapse all
|
||||||
|
contents.forEach(content => content.classList.remove('show'));
|
||||||
|
icons.forEach(icon => icon.classList.remove('rotated'));
|
||||||
|
button.textContent = 'Expand All Steps';
|
||||||
|
} else {
|
||||||
|
// Expand all
|
||||||
|
contents.forEach(content => content.classList.add('show'));
|
||||||
|
icons.forEach(icon => icon.classList.add('rotated'));
|
||||||
|
button.textContent = 'Collapse All Steps';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle all actions
|
||||||
|
function toggleAllActions() {
|
||||||
|
const contents = document.querySelectorAll('.action-content');
|
||||||
|
const toggles = document.querySelectorAll('.action-toggle');
|
||||||
|
const button = document.getElementById('toggleActionsBtn');
|
||||||
|
|
||||||
|
// Check if any action is currently expanded
|
||||||
|
const anyExpanded = Array.from(contents).some(content => content.classList.contains('expanded'));
|
||||||
|
|
||||||
|
if (anyExpanded) {
|
||||||
|
// Collapse all
|
||||||
|
contents.forEach(content => content.classList.remove('expanded'));
|
||||||
|
toggles.forEach(toggle => {
|
||||||
|
toggle.classList.add('collapsed');
|
||||||
|
toggle.textContent = '▶';
|
||||||
|
});
|
||||||
|
button.textContent = 'Expand All Actions';
|
||||||
|
} else {
|
||||||
|
// Expand all
|
||||||
|
contents.forEach(content => content.classList.add('expanded'));
|
||||||
|
toggles.forEach(toggle => {
|
||||||
|
toggle.classList.remove('collapsed');
|
||||||
|
toggle.textContent = '▼';
|
||||||
|
});
|
||||||
|
button.textContent = 'Collapse All Actions';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-expand all steps on load to show actions
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Expand all steps to show the actions list
|
||||||
|
const contents = document.querySelectorAll('.step-content');
|
||||||
|
const icons = document.querySelectorAll('.toggle-icon');
|
||||||
|
const stepsButton = document.getElementById('toggleStepsBtn');
|
||||||
|
|
||||||
contents.forEach(content => content.classList.add('show'));
|
contents.forEach(content => content.classList.add('show'));
|
||||||
icons.forEach(icon => icon.classList.add('rotated'));
|
icons.forEach(icon => icon.classList.add('rotated'));
|
||||||
}
|
|
||||||
|
|
||||||
// Collapse all steps
|
// Update button text to reflect current state (steps are expanded)
|
||||||
function collapseAll() {
|
if (stepsButton) {
|
||||||
const contents = document.querySelectorAll('.step-content');
|
stepsButton.textContent = 'Collapse All Steps';
|
||||||
const icons = document.querySelectorAll('.toggle-icon');
|
|
||||||
|
|
||||||
contents.forEach(content => content.classList.remove('show'));
|
|
||||||
icons.forEach(icon => icon.classList.remove('rotated'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-expand failed steps on load
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const failedSteps = document.querySelectorAll('.step-container .status-badge.failure');
|
|
||||||
failedSteps.forEach(badge => {
|
|
||||||
const stepContainer = badge.closest('.step-container');
|
|
||||||
const stepHeader = stepContainer.querySelector('.step-header');
|
|
||||||
if (stepHeader) {
|
|
||||||
stepHeader.click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+17
-17
@@ -84,25 +84,25 @@ func TestAndroidAction(t *testing.T) {
|
|||||||
|
|
||||||
func TestStartToGoal(t *testing.T) {
|
func TestStartToGoal(t *testing.T) {
|
||||||
userInstruction := `连连看是一款经典的益智消除类小游戏,通常以图案或图标为主要元素。以下是连连看的基本规则说明:
|
userInstruction := `连连看是一款经典的益智消除类小游戏,通常以图案或图标为主要元素。以下是连连看的基本规则说明:
|
||||||
1. 游戏目标: 玩家需要通过连接相同的图案或图标,将它们从游戏界面中消除。
|
1. 游戏目标: 玩家需要通过连接相同的图案或图标,将它们从游戏界面中消除。
|
||||||
2. 连接规则:
|
2. 连接规则:
|
||||||
- 两个相同的图案可以通过不超过三条直线连接。
|
- 两个相同的图案可以通过不超过三条直线连接。
|
||||||
- 连接线可以水平或垂直,但不能斜线,也不能跨过其他图案。
|
- 连接线可以水平或垂直,但不能斜线,也不能跨过其他图案。
|
||||||
- 连接线的转折次数不能超过两次。
|
- 连接线的转折次数不能超过两次。
|
||||||
3. 游戏界面:
|
3. 游戏界面:
|
||||||
- 游戏界面通常是一个矩形区域,内含多个图案或图标,排列成行和列。
|
- 游戏界面通常是一个矩形区域,内含多个图案或图标,排列成行和列。
|
||||||
- 图案或图标在未选中状态下背景为白色,选中状态下背景为绿色。
|
- 图案或图标在未选中状态下背景为白色,选中状态下背景为绿色。
|
||||||
4. 重试机制:
|
4. 重试机制:
|
||||||
- 游戏失败后,可以点击「立即复活」按钮,观看视频广告;30秒,点击屏幕右上角关闭图标后可继续游戏。
|
- 游戏失败后,可以点击「立即复活」按钮,观看视频广告;30秒,点击屏幕右上角关闭图标后可继续游戏。
|
||||||
- 若无法再复活,可以点击「立即挑战」按钮,重新开始游戏。
|
- 若无法再复活,可以点击「立即挑战」按钮,重新开始游戏。
|
||||||
|
|
||||||
注意事项:
|
注意事项:
|
||||||
1、当连接错误时,顶部的红心会减少一个,需及时调整策略,避免红心变为0个后游戏失败
|
1、当连接错误时,顶部的红心会减少一个,需及时调整策略,避免红心变为0个后游戏失败
|
||||||
2、不要连续 2 次点击同一个图案
|
2、不要连续 2 次点击同一个图案
|
||||||
3、不要犯重复的错误
|
3、不要犯重复的错误
|
||||||
|
|
||||||
请严格按照以上游戏规则,开始游戏
|
请严格按照以上游戏规则,开始游戏
|
||||||
`
|
`
|
||||||
|
|
||||||
testCase := &hrp.TestCase{
|
testCase := &hrp.TestCase{
|
||||||
Config: hrp.NewConfig("run ui action with start to goal").
|
Config: hrp.NewConfig("run ui action with start to goal").
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ func NewLLMContentParser(modelType option.LLMServiceType) LLMContentParser {
|
|||||||
switch modelType {
|
switch modelType {
|
||||||
case option.DOUBAO_1_5_UI_TARS_250428:
|
case option.DOUBAO_1_5_UI_TARS_250428:
|
||||||
return &UITARSContentParser{
|
return &UITARSContentParser{
|
||||||
|
modelType: modelType,
|
||||||
systemPrompt: doubao_1_5_ui_tars_planning_prompt,
|
systemPrompt: doubao_1_5_ui_tars_planning_prompt,
|
||||||
actionMapping: doubao_1_5_ui_tars_action_mapping,
|
actionMapping: doubao_1_5_ui_tars_action_mapping,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return &JSONContentParser{
|
return &JSONContentParser{
|
||||||
|
modelType: modelType,
|
||||||
systemPrompt: doubao_1_5_thinking_vision_pro_planning_prompt,
|
systemPrompt: doubao_1_5_thinking_vision_pro_planning_prompt,
|
||||||
actionMapping: doubao_1_5_thinking_vision_pro_action_mapping,
|
actionMapping: doubao_1_5_thinking_vision_pro_action_mapping,
|
||||||
}
|
}
|
||||||
@@ -34,6 +36,7 @@ func NewLLMContentParser(modelType option.LLMServiceType) LLMContentParser {
|
|||||||
|
|
||||||
// JSONContentParser parses the response as JSON string format
|
// JSONContentParser parses the response as JSON string format
|
||||||
type JSONContentParser struct {
|
type JSONContentParser struct {
|
||||||
|
modelType option.LLMServiceType
|
||||||
systemPrompt string
|
systemPrompt string
|
||||||
actionMapping map[string]option.ActionName
|
actionMapping map[string]option.ActionName
|
||||||
}
|
}
|
||||||
@@ -98,5 +101,6 @@ func (p *JSONContentParser) Parse(content string, size types.Size) (*PlanningRes
|
|||||||
ToolCalls: toolCalls,
|
ToolCalls: toolCalls,
|
||||||
Thought: jsonResponse.Thought,
|
Thought: jsonResponse.Thought,
|
||||||
Content: content,
|
Content: content,
|
||||||
|
ModelName: string(p.modelType),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const (
|
|||||||
|
|
||||||
// UITARSContentParser parses the Thought/Action format response
|
// UITARSContentParser parses the Thought/Action format response
|
||||||
type UITARSContentParser struct {
|
type UITARSContentParser struct {
|
||||||
|
modelType option.LLMServiceType
|
||||||
systemPrompt string
|
systemPrompt string
|
||||||
actionMapping map[string]option.ActionName
|
actionMapping map[string]option.ActionName
|
||||||
}
|
}
|
||||||
@@ -55,6 +56,7 @@ func (p *UITARSContentParser) Parse(content string, size types.Size) (*PlanningR
|
|||||||
ToolCalls: toolCalls,
|
ToolCalls: toolCalls,
|
||||||
Thought: thought,
|
Thought: thought,
|
||||||
Content: content,
|
Content: content,
|
||||||
|
ModelName: string(p.modelType),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type PlanningResult struct {
|
|||||||
Thought string `json:"thought"`
|
Thought string `json:"thought"`
|
||||||
Content string `json:"content"` // original content from model
|
Content string `json:"content"` // original content from model
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
|
ModelName string `json:"model_name"` // model name used for planning
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlanner(ctx context.Context, modelConfig *ModelConfig) (*Planner, error) {
|
func NewPlanner(ctx context.Context, modelConfig *ModelConfig) (*Planner, error) {
|
||||||
@@ -132,6 +133,7 @@ func (p *Planner) Call(ctx context.Context, opts *PlanningOptions) (*PlanningRes
|
|||||||
result := &PlanningResult{
|
result := &PlanningResult{
|
||||||
ToolCalls: message.ToolCalls,
|
ToolCalls: message.ToolCalls,
|
||||||
Thought: message.Content,
|
Thought: message.Content,
|
||||||
|
ModelName: string(p.modelConfig.ModelType),
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
@@ -142,6 +144,7 @@ func (p *Planner) Call(ctx context.Context, opts *PlanningOptions) (*PlanningRes
|
|||||||
result = &PlanningResult{
|
result = &PlanningResult{
|
||||||
Thought: message.Content,
|
Thought: message.Content,
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
ModelName: string(p.modelConfig.ModelType),
|
||||||
}
|
}
|
||||||
log.Debug().Str("reason", err.Error()).Msg("parse content to actions failed")
|
log.Debug().Str("reason", err.Error()).Msg("parse content to actions failed")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ func (dExt *XTDriver) StartToGoal(ctx context.Context, prompt string, opts ...op
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Plan next action with history reset on first attempt
|
// Plan next action with history reset on first attempt
|
||||||
|
planningStartTime := time.Now()
|
||||||
planningOpts := opts
|
planningOpts := opts
|
||||||
if attempt == 1 {
|
if attempt == 1 {
|
||||||
// Add ResetHistory option for the first attempt
|
// Add ResetHistory option for the first attempt
|
||||||
@@ -52,6 +53,9 @@ func (dExt *XTDriver) StartToGoal(ctx context.Context, prompt string, opts ...op
|
|||||||
ActionName: "plan_next_action",
|
ActionName: "plan_next_action",
|
||||||
Arguments: prompt,
|
Arguments: prompt,
|
||||||
Error: err,
|
Error: err,
|
||||||
|
StartTime: planningStartTime.Unix(),
|
||||||
|
Elapsed: time.Since(planningStartTime).Milliseconds(),
|
||||||
|
SessionData: dExt.GetSession().GetData(true),
|
||||||
})
|
})
|
||||||
return allSubActions, err
|
return allSubActions, err
|
||||||
}
|
}
|
||||||
@@ -59,6 +63,17 @@ func (dExt *XTDriver) StartToGoal(ctx context.Context, prompt string, opts ...op
|
|||||||
// Check if task is finished BEFORE executing actions
|
// Check if task is finished BEFORE executing actions
|
||||||
if dExt.isTaskFinished(result) {
|
if dExt.isTaskFinished(result) {
|
||||||
log.Info().Msg("task finished, stopping StartToGoal")
|
log.Info().Msg("task finished, stopping StartToGoal")
|
||||||
|
// Create a sub-action result to record the planning result even when task is finished
|
||||||
|
subActionResult := &SubActionResult{
|
||||||
|
ActionName: "plan_next_action",
|
||||||
|
Arguments: prompt,
|
||||||
|
StartTime: planningStartTime.Unix(),
|
||||||
|
Elapsed: time.Since(planningStartTime).Milliseconds(),
|
||||||
|
Thought: result.Thought,
|
||||||
|
ModelName: result.ModelName,
|
||||||
|
SessionData: dExt.GetSession().GetData(true),
|
||||||
|
}
|
||||||
|
allSubActions = append(allSubActions, subActionResult)
|
||||||
return allSubActions, nil
|
return allSubActions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +94,7 @@ func (dExt *XTDriver) StartToGoal(ctx context.Context, prompt string, opts ...op
|
|||||||
Arguments: toolCall.Function.Arguments,
|
Arguments: toolCall.Function.Arguments,
|
||||||
StartTime: subActionStartTime.Unix(),
|
StartTime: subActionStartTime.Unix(),
|
||||||
Thought: result.Thought,
|
Thought: result.Thought,
|
||||||
|
ModelName: result.ModelName,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dExt.invokeToolCall(ctx, toolCall); err != nil {
|
if err := dExt.invokeToolCall(ctx, toolCall); err != nil {
|
||||||
@@ -86,6 +102,7 @@ func (dExt *XTDriver) StartToGoal(ctx context.Context, prompt string, opts ...op
|
|||||||
allSubActions = append(allSubActions, subActionResult)
|
allSubActions = append(allSubActions, subActionResult)
|
||||||
return allSubActions, err
|
return allSubActions, err
|
||||||
}
|
}
|
||||||
|
subActionResult.Elapsed = time.Since(subActionStartTime).Milliseconds()
|
||||||
|
|
||||||
// Collect sub-action specific attachments and reset session data
|
// Collect sub-action specific attachments and reset session data
|
||||||
subActionResult.SessionData = dExt.GetSession().GetData(true) // reset after getting data
|
subActionResult.SessionData = dExt.GetSession().GetData(true) // reset after getting data
|
||||||
@@ -227,6 +244,7 @@ type SubActionResult struct {
|
|||||||
Elapsed int64 `json:"elapsed_ms"` // sub-action elapsed time(ms)
|
Elapsed int64 `json:"elapsed_ms"` // sub-action elapsed time(ms)
|
||||||
Error error `json:"error,omitempty"` // sub-action execution result
|
Error error `json:"error,omitempty"` // sub-action execution result
|
||||||
Thought string `json:"thought,omitempty"` // sub-action thought
|
Thought string `json:"thought,omitempty"` // sub-action thought
|
||||||
|
ModelName string `json:"model_name,omitempty"` // model name used for AI actions
|
||||||
SessionData
|
SessionData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user