Skip to content

Commit 9bba002

Browse files
committed
feat(agents): add Codex quick use for prompts
1 parent 4b8566c commit 9bba002

5 files changed

Lines changed: 195 additions & 2 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
const CODEX_NEW_THREAD_URL = 'codex://threads/new';
4+
5+
function buildCodexNewThreadUrl({ prompt, originUrl }) {
6+
const params = new URLSearchParams();
7+
params.set('prompt', String(prompt || ''));
8+
9+
if (originUrl) {
10+
params.set('originUrl', String(originUrl));
11+
}
12+
13+
return `${CODEX_NEW_THREAD_URL}?${params.toString()}`;
14+
}
15+
16+
function buildAgentDetailCodexPrompt(detail = {}, _originUrl, selectedPrompt) {
17+
const firstPrompt = selectedPrompt || (Array.isArray(detail.prompts) ? detail.prompts[0] : null);
18+
return firstPrompt ? String(firstPrompt.prompt || '') : '';
19+
}
20+
21+
module.exports = {
22+
buildAgentDetailCodexPrompt,
23+
buildCodexNewThreadUrl,
24+
};

app/web/pages/agents/detail/AgentDetailContent.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useEffect, useMemo, useState } from 'react';
22
import {
3+
CodeOutlined,
34
CopyOutlined,
45
DownloadOutlined,
56
MessageOutlined,
@@ -13,6 +14,7 @@ import { Button, Card, Empty, message, Spin, Tabs, Tag, Typography } from 'antd'
1314
import { API } from '@/api';
1415
import { copyToClipboard } from '@/utils/copyUtils';
1516
import { safeOpenUrl } from '@/utils/safeOpenUrl';
17+
import { buildAgentDetailCodexPrompt, buildCodexNewThreadUrl } from '../codex-button-utils';
1618
import type { AgentCapability, AgentDetail, AgentItem, AgentSkillRelation } from '../types';
1719
import './style.scss';
1820

@@ -146,6 +148,16 @@ const AgentDetailContent: React.FC<AgentDetailContentProps> = ({ name, history }
146148
? `curl -fsSL ${currentOrigin}/agent-market/install.sh | bash -s -- ${detail.name}`
147149
: '';
148150

151+
const openCodexInstall = (selectedPrompt?: { title?: string; prompt?: string }) => {
152+
if (!detail) return;
153+
154+
const originUrl = typeof window !== 'undefined' ? window.location.href : '';
155+
const prompt = buildAgentDetailCodexPrompt(detail, originUrl, selectedPrompt);
156+
const codexUrl = buildCodexNewThreadUrl({ prompt, originUrl });
157+
158+
window.location.href = codexUrl;
159+
};
160+
149161
if (loading) {
150162
return (
151163
<div className="page-agent-detail loading-wrap">
@@ -364,6 +376,18 @@ const AgentDetailContent: React.FC<AgentDetailContentProps> = ({ name, history }
364376
{item.prompt}
365377
</Paragraph>
366378
</div>
379+
<Button
380+
size="small"
381+
className="agent-question-quick-use"
382+
icon={
383+
<span className="agent-question-quick-use-icon">
384+
<CodeOutlined />
385+
</span>
386+
}
387+
onClick={() => openCodexInstall(item)}
388+
>
389+
快捷使用
390+
</Button>
367391
</div>
368392
</Card>
369393
)

app/web/pages/agents/detail/style.scss

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,15 @@
343343
}
344344
.agent-question-card-body {
345345
display: grid;
346-
grid-template-columns: 32px minmax(0, 1fr);
346+
grid-template-columns: 32px minmax(0, 1fr) auto;
347347
align-items: center;
348-
gap: 12px;
348+
gap: 16px;
349349
}
350350
.agent-question-copy {
351351
flex: 1;
352+
display: flex;
353+
flex-direction: column;
354+
align-items: flex-start;
352355
.ant-typography:first-child {
353356
display: block;
354357
margin-bottom: 4px;
@@ -362,6 +365,48 @@
362365
font-size: 14px;
363366
}
364367
}
368+
.agent-question-quick-use {
369+
display: inline-flex;
370+
align-items: center;
371+
justify-content: center;
372+
height: 36px;
373+
padding: 0 16px 0 12px;
374+
border-color: #D8DFEA;
375+
border-radius: 10px;
376+
color: #344054;
377+
background: #FFF;
378+
font-weight: 600;
379+
white-space: nowrap;
380+
box-shadow: none;
381+
transition:
382+
transform 0.18s ease,
383+
border-color 0.18s ease,
384+
color 0.18s ease,
385+
background 0.18s ease,
386+
box-shadow 0.18s ease;
387+
&:hover,
388+
&:focus {
389+
border-color: #F6B85A;
390+
color: #B66A00;
391+
background: #FFF9EF;
392+
box-shadow: 0 6px 14px rgba(245, 158, 11, 0.12);
393+
transform: translateY(-1px);
394+
}
395+
&:active {
396+
transform: translateY(0);
397+
box-shadow: 0 3px 8px rgba(245, 158, 11, 0.1);
398+
}
399+
.anticon {
400+
margin-right: 8px;
401+
}
402+
}
403+
.agent-question-quick-use-icon {
404+
display: inline-flex;
405+
align-items: center;
406+
justify-content: center;
407+
color: #F59E0B;
408+
font-size: 14px;
409+
}
365410
.agent-skill-grid {
366411
display: grid;
367412
grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -465,5 +510,12 @@
465510
flex-direction: column;
466511
align-items: flex-start;
467512
}
513+
.agent-question-card-body {
514+
grid-template-columns: 32px minmax(0, 1fr);
515+
}
516+
.agent-question-quick-use {
517+
grid-column: 2;
518+
justify-self: flex-end;
519+
}
468520
}
469521
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const test = require('node:test');
2+
const assert = require('node:assert/strict');
3+
4+
const {
5+
buildAgentDetailCodexPrompt,
6+
buildCodexNewThreadUrl,
7+
} = require('../app/web/pages/agents/codex-button-utils');
8+
9+
test('buildCodexNewThreadUrl builds a codex new thread deep link with encoded prompt and origin', () => {
10+
const url = buildCodexNewThreadUrl({
11+
prompt: '打开 Agent 市场\n使用示例',
12+
originUrl: 'http://10.10.10.168:7001/page/agents?keyword=AI Agent',
13+
});
14+
15+
assert.equal(url.startsWith('codex://threads/new?'), true);
16+
assert.equal(url.includes('prompt='), true);
17+
assert.equal(url.includes('originUrl='), true);
18+
assert.equal(url.includes('AI+Agent'), true);
19+
assert.equal(url.includes('\n'), false);
20+
});
21+
22+
test('buildAgentDetailCodexPrompt returns only the opening question prompt', () => {
23+
const prompt = buildAgentDetailCodexPrompt(
24+
{
25+
displayName: 'Bug 修复 Agent',
26+
name: 'bugfix-agent',
27+
description: '用于修复 Bug',
28+
entrypoint: { slug: 'bugfix-workflow', name: 'Bug 修复工作流' },
29+
dependencies: [
30+
{ slug: 'zentao-api', name: '禅道 API' },
31+
{ slug: 'gitlab-mr-ci-watch', name: 'MR CI 观察' },
32+
],
33+
prompts: [{ title: '修复 Bug', prompt: '$bugfix-workflow 12345' }],
34+
},
35+
'http://10.10.10.168:7001/page/agents/bugfix-agent'
36+
);
37+
38+
assert.equal(prompt, '$bugfix-workflow 12345');
39+
});
40+
41+
test('buildAgentDetailCodexPrompt can use the selected opening question', () => {
42+
const prompt = buildAgentDetailCodexPrompt(
43+
{
44+
displayName: 'Bug 修复 Agent',
45+
name: 'bugfix-agent',
46+
prompts: [{ title: '默认问题', prompt: '$bugfix-workflow 默认' }],
47+
},
48+
'http://10.10.10.168:7001/page/agents/bugfix-agent',
49+
{ title: '自然语言', prompt: '帮我修 bug,禅道 Bug ID 是 156343' }
50+
);
51+
52+
assert.equal(prompt, '帮我修 bug,禅道 Bug ID 是 156343');
53+
});

test/agent-detail-layout.test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,46 @@ test('Agent 详情右侧展示可复制的自动安装命令', () => {
240240
);
241241
});
242242

243+
test('Agent 开场问题卡片提供调起 Codex 的快捷使用入口', () => {
244+
const content = fs.readFileSync(
245+
path.join(__dirname, '../app/web/pages/agents/detail/AgentDetailContent.tsx'),
246+
'utf8'
247+
);
248+
const styleContent = fs.readFileSync(
249+
path.join(__dirname, '../app/web/pages/agents/detail/style.scss'),
250+
'utf8'
251+
);
252+
253+
assert.equal(
254+
content.includes('buildAgentDetailCodexPrompt') &&
255+
content.includes('buildCodexNewThreadUrl') &&
256+
content.includes('className="agent-question-quick-use"') &&
257+
content.includes('agent-question-quick-use-icon') &&
258+
content.includes('onClick={() => openCodexInstall(item)}') &&
259+
content.includes('快捷使用'),
260+
true,
261+
'开场问题卡片需要提供快捷使用按钮并调起 Codex'
262+
);
263+
assert.equal(
264+
content.includes('className="agent-quick-use"'),
265+
false,
266+
'右侧不应再展示独立快捷使用按钮'
267+
);
268+
assert.equal(
269+
styleContent.includes('.agent-question-quick-use') &&
270+
styleContent.includes('grid-template-columns: 32px minmax(0, 1fr) auto;') &&
271+
styleContent.includes('align-items: center;') &&
272+
styleContent.includes('&:hover,') &&
273+
styleContent.includes('transform: translateY(-1px);') &&
274+
styleContent.includes('border-color: #D8DFEA;') &&
275+
styleContent.includes('.agent-question-quick-use-icon') &&
276+
!styleContent.includes('border: 1px solid #F59E0B;') &&
277+
!styleContent.includes('background: rgba(245, 158, 11, 0.12);'),
278+
true,
279+
'开场问题快捷使用按钮需要左右布局、垂直居中并提供克制的 hover 样式'
280+
);
281+
});
282+
243283
test('Agent 详情右侧提供当前原始 ZIP 下载入口', () => {
244284
const content = fs.readFileSync(
245285
path.join(__dirname, '../app/web/pages/agents/detail/AgentDetailContent.tsx'),

0 commit comments

Comments
 (0)