a2acalling 0.6.48 → 0.6.50
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/bin/cli.js +79 -2
- package/docs/plans/2026-02-16-auto-updater.md +1284 -0
- package/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
- package/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
- package/docs/prompts/e2e-test-agent.md +368 -0
- package/docs/protocol.md +121 -0
- package/package.json +1 -1
- package/scripts/install-skills.js +80 -0
- package/scripts/postinstall.js +12 -0
- package/src/dashboard/public/app.js +108 -1
- package/src/dashboard/public/index.html +9 -0
- package/src/dashboard/public/style.css +27 -0
- package/src/lib/claude-subagent.js +6 -5
- package/src/lib/config.js +42 -0
- package/src/lib/conversation-driver.js +74 -24
- package/src/lib/openclaw-integration.js +22 -66
- package/src/lib/runtime-adapter.js +8 -3
- package/src/lib/summary-formatter.js +168 -0
- package/src/lib/summary-prompt.js +203 -0
- package/src/lib/tokens.js +13 -1
- package/src/lib/turn-timeout.js +52 -0
- package/src/lib/update-checker.js +93 -0
- package/src/lib/update-manager.js +313 -0
- package/src/routes/a2a.js +9 -1
- package/src/routes/dashboard.js +103 -1
- package/src/server.js +130 -26
package/src/server.js
CHANGED
|
@@ -23,6 +23,11 @@ const {
|
|
|
23
23
|
const { findAvailablePort } = require('./lib/port-scanner');
|
|
24
24
|
const { createLogger } = require('./lib/logger');
|
|
25
25
|
const { writePidFile, removePidFile } = require('./lib/pid-file');
|
|
26
|
+
const { buildUnifiedSummaryPrompt } = require('./lib/summary-prompt');
|
|
27
|
+
const { A2AConfig } = require('./lib/config');
|
|
28
|
+
const { UpdateManager } = require('./lib/update-manager');
|
|
29
|
+
const { spawn } = require('child_process');
|
|
30
|
+
const { resolveTurnTimeoutMs } = require('./lib/turn-timeout');
|
|
26
31
|
|
|
27
32
|
const DEFAULT_PORTS = [80, 3001, 8080, 8443, 9001];
|
|
28
33
|
const requestedPort = process.env.PORT ? parseInt(process.env.PORT, 10)
|
|
@@ -61,6 +66,7 @@ function loadAgentContext() {
|
|
|
61
66
|
|
|
62
67
|
const agentContext = loadAgentContext();
|
|
63
68
|
const tokenStore = new TokenStore();
|
|
69
|
+
const config = new A2AConfig();
|
|
64
70
|
const runtime = createRuntimeAdapter({
|
|
65
71
|
workspaceDir,
|
|
66
72
|
agentContext,
|
|
@@ -115,6 +121,15 @@ function readPositiveIntEnv(name, fallback) {
|
|
|
115
121
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
116
122
|
}
|
|
117
123
|
|
|
124
|
+
function resolveConfiguredTurnTimeoutMs() {
|
|
125
|
+
try {
|
|
126
|
+
const defaults = config.getDefaults?.() || {};
|
|
127
|
+
return defaults.turnTimeoutMs ?? defaults.turn_timeout_ms ?? null;
|
|
128
|
+
} catch (err) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
118
133
|
function resolveCollabMode() {
|
|
119
134
|
const raw = String(process.env.A2A_COLLAB_MODE || 'adaptive').trim().toLowerCase();
|
|
120
135
|
if (raw === 'deep_dive' || raw === 'deep-dive') {
|
|
@@ -578,6 +593,10 @@ async function callAgent(message, a2aContext) {
|
|
|
578
593
|
: buildConnectionPrompt(promptOptions);
|
|
579
594
|
|
|
580
595
|
const sessionId = `a2a-${conversationId}`;
|
|
596
|
+
const claudeTurnTimeoutMs = resolveTurnTimeoutMs({
|
|
597
|
+
tokenTimeoutMs: a2aContext.timeout_ms,
|
|
598
|
+
configTimeoutMs: resolveConfiguredTurnTimeoutMs()
|
|
599
|
+
});
|
|
581
600
|
|
|
582
601
|
try {
|
|
583
602
|
callLogger.info('Handling inbound call turn', {
|
|
@@ -595,12 +614,13 @@ async function callAgent(message, a2aContext) {
|
|
|
595
614
|
prompt,
|
|
596
615
|
message,
|
|
597
616
|
caller: a2aContext.caller || {},
|
|
598
|
-
timeoutMs: 65000,
|
|
617
|
+
timeoutMs: runtime.mode === 'claude' ? claudeTurnTimeoutMs : 65000,
|
|
599
618
|
context: {
|
|
600
619
|
conversationId,
|
|
601
620
|
tier: tierInfo,
|
|
602
621
|
ownerName: agentContext.owner,
|
|
603
622
|
allowedTopics: a2aContext.allowed_topics || [],
|
|
623
|
+
timeoutMs: runtime.mode === 'claude' ? claudeTurnTimeoutMs : 65000,
|
|
604
624
|
traceId,
|
|
605
625
|
requestId
|
|
606
626
|
}
|
|
@@ -691,30 +711,61 @@ async function callAgent(message, a2aContext) {
|
|
|
691
711
|
* Generate strategic summary via sub-agent
|
|
692
712
|
*/
|
|
693
713
|
async function generateSummary(messages, callerInfo) {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
714
|
+
// Look up collaboration state if we have a conversation_id
|
|
715
|
+
const conversationId = callerInfo?.conversation_id || callerInfo?.conversationId;
|
|
716
|
+
let collaborationState = null;
|
|
717
|
+
if (conversationId) {
|
|
718
|
+
const collabSession = collaborationSessions.get(conversationId);
|
|
719
|
+
if (collabSession) {
|
|
720
|
+
collaborationState = {
|
|
721
|
+
phase: collabSession.phase,
|
|
722
|
+
overlapScore: collabSession.overlapScore,
|
|
723
|
+
turnCount: collabSession.turnCount,
|
|
724
|
+
activeThreads: collabSession.activeThreads,
|
|
725
|
+
candidateCollaborations: collabSession.candidateCollaborations,
|
|
726
|
+
closeSignal: collabSession.closeSignal
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
}
|
|
707
730
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
731
|
+
// Load disclosure manifest for the caller's tier
|
|
732
|
+
const tier = callerInfo?.tier || 'public';
|
|
733
|
+
let disclosure = null;
|
|
734
|
+
try {
|
|
735
|
+
const tierTopics = getTopicsForTier(tier);
|
|
736
|
+
if (tierTopics) {
|
|
737
|
+
disclosure = {
|
|
738
|
+
topics: tierTopics.topics || [],
|
|
739
|
+
objectives: tierTopics.objectives || [],
|
|
740
|
+
doNotDiscuss: tierTopics.do_not_discuss || [],
|
|
741
|
+
neverDisclose: tierTopics.never_disclose || []
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
} catch (e) {
|
|
745
|
+
// Disclosure is optional — continue without it
|
|
746
|
+
}
|
|
716
747
|
|
|
717
|
-
|
|
748
|
+
// Build transcript in unified format
|
|
749
|
+
const transcript = messages.map(m => ({
|
|
750
|
+
direction: m.direction,
|
|
751
|
+
content: m.content
|
|
752
|
+
}));
|
|
753
|
+
|
|
754
|
+
const prompt = buildUnifiedSummaryPrompt({
|
|
755
|
+
transcript,
|
|
756
|
+
callerInfo: {
|
|
757
|
+
name: callerInfo?.name || null,
|
|
758
|
+
owner: callerInfo?.owner || null,
|
|
759
|
+
context: callerInfo?.context || null
|
|
760
|
+
},
|
|
761
|
+
disclosure,
|
|
762
|
+
collaborationState,
|
|
763
|
+
ownerContext: {
|
|
764
|
+
agentName: agentContext.name,
|
|
765
|
+
ownerName: agentContext.owner,
|
|
766
|
+
goals: []
|
|
767
|
+
}
|
|
768
|
+
});
|
|
718
769
|
|
|
719
770
|
try {
|
|
720
771
|
return await runtime.summarize({
|
|
@@ -723,13 +774,13 @@ Be concise but specific. No filler.`;
|
|
|
723
774
|
messages,
|
|
724
775
|
callerInfo,
|
|
725
776
|
traceId: callerInfo?.trace_id || callerInfo?.traceId,
|
|
726
|
-
conversationId
|
|
777
|
+
conversationId
|
|
727
778
|
});
|
|
728
779
|
} catch (err) {
|
|
729
780
|
logger.error('Summary generation failed', {
|
|
730
781
|
event: 'summary_generation_failed',
|
|
731
782
|
traceId: callerInfo?.trace_id || callerInfo?.traceId,
|
|
732
|
-
conversationId
|
|
783
|
+
conversationId,
|
|
733
784
|
error_code: 'SUMMARY_GENERATION_FAILED',
|
|
734
785
|
hint: 'Check summarizer runtime and command configuration for summary stage.',
|
|
735
786
|
error: err,
|
|
@@ -773,17 +824,23 @@ async function notifyOwner({ level, token, caller, message, conversation_id, tra
|
|
|
773
824
|
|
|
774
825
|
const app = express();
|
|
775
826
|
app.use(express.json());
|
|
827
|
+
let activeCallMonitor = null;
|
|
828
|
+
let updateManager = null;
|
|
776
829
|
|
|
777
830
|
// Minimal owner dashboard (local by default unless A2A_ADMIN_TOKEN is provided)
|
|
778
831
|
// All routes under /api/a2a/* so reverse proxy config stays simple.
|
|
779
832
|
app.use('/api/a2a/dashboard', createDashboardApiRouter({
|
|
780
833
|
tokenStore,
|
|
781
834
|
agentContext,
|
|
835
|
+
config,
|
|
836
|
+
getUpdateManager: () => updateManager,
|
|
782
837
|
logger: logger.child({ component: 'a2a.dashboard' })
|
|
783
838
|
}));
|
|
784
839
|
app.use('/api/a2a/dashboard', createDashboardUiRouter({
|
|
785
840
|
tokenStore,
|
|
786
841
|
agentContext,
|
|
842
|
+
config,
|
|
843
|
+
getUpdateManager: () => updateManager,
|
|
787
844
|
logger: logger.child({ component: 'a2a.dashboard' })
|
|
788
845
|
}));
|
|
789
846
|
|
|
@@ -802,6 +859,9 @@ app.use('/callbook', createCallbookRouter());
|
|
|
802
859
|
app.use('/api/a2a', createRoutes({
|
|
803
860
|
tokenStore,
|
|
804
861
|
logger: logger.child({ component: 'a2a.routes' }),
|
|
862
|
+
onCallMonitor: (monitor) => {
|
|
863
|
+
activeCallMonitor = monitor;
|
|
864
|
+
},
|
|
805
865
|
|
|
806
866
|
async handleMessage(message, context, options) {
|
|
807
867
|
const traceId = context.trace_id || null;
|
|
@@ -905,6 +965,50 @@ async function startServer() {
|
|
|
905
965
|
}
|
|
906
966
|
});
|
|
907
967
|
writePidFile(process.pid);
|
|
968
|
+
|
|
969
|
+
if (!updateManager) {
|
|
970
|
+
const pkg = require('../package.json');
|
|
971
|
+
const restartFn = async () => {
|
|
972
|
+
const cliPath = path.join(__dirname, '..', 'bin', 'cli.js');
|
|
973
|
+
const helperScript = `
|
|
974
|
+
const { spawn } = require('child_process');
|
|
975
|
+
const startNext = () => {
|
|
976
|
+
const child = spawn(process.execPath, [${JSON.stringify(cliPath)}, 'server', '--port', ${JSON.stringify(String(port))}], {
|
|
977
|
+
detached: true,
|
|
978
|
+
stdio: 'ignore',
|
|
979
|
+
env: process.env
|
|
980
|
+
});
|
|
981
|
+
child.unref();
|
|
982
|
+
process.exit(0);
|
|
983
|
+
};
|
|
984
|
+
setTimeout(startNext, 1500);
|
|
985
|
+
`;
|
|
986
|
+
const helper = spawn(process.execPath, ['-e', helperScript], {
|
|
987
|
+
detached: true,
|
|
988
|
+
stdio: 'ignore',
|
|
989
|
+
env: process.env
|
|
990
|
+
});
|
|
991
|
+
helper.unref();
|
|
992
|
+
setTimeout(() => {
|
|
993
|
+
process.kill(process.pid, 'SIGTERM');
|
|
994
|
+
}, 150);
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
updateManager = new UpdateManager({
|
|
998
|
+
currentVersion: pkg.version,
|
|
999
|
+
config,
|
|
1000
|
+
logger: logger.child({ component: 'a2a.updater' }),
|
|
1001
|
+
getCallMonitor: () => activeCallMonitor,
|
|
1002
|
+
restartFn
|
|
1003
|
+
});
|
|
1004
|
+
updateManager.start();
|
|
1005
|
+
updateManager.triggerCheck({ reason: 'startup' }).catch((err) => {
|
|
1006
|
+
logger.warn('Initial auto-update check failed', {
|
|
1007
|
+
event: 'updater_startup_check_failed',
|
|
1008
|
+
error: err
|
|
1009
|
+
});
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
908
1012
|
});
|
|
909
1013
|
|
|
910
1014
|
server.on('error', (err) => {
|
|
@@ -920,8 +1024,8 @@ async function startServer() {
|
|
|
920
1024
|
throw err;
|
|
921
1025
|
});
|
|
922
1026
|
|
|
923
|
-
// Graceful shutdown: clean up PID file
|
|
924
1027
|
function shutdown() {
|
|
1028
|
+
if (updateManager) updateManager.stop();
|
|
925
1029
|
removePidFile();
|
|
926
1030
|
server.close(() => process.exit(0));
|
|
927
1031
|
// Force exit after 5s if connections won't close
|