@nex-ai/nex 0.1.22 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/dist/agent/adoption.d.ts +23 -0
- package/dist/agent/adoption.js +87 -0
- package/dist/agent/adoption.js.map +1 -0
- package/dist/agent/gossip.d.ts +17 -0
- package/dist/agent/gossip.js +48 -0
- package/dist/agent/gossip.js.map +1 -0
- package/dist/agent/loop.d.ts +59 -0
- package/dist/agent/loop.js +389 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/queues.d.ts +16 -0
- package/dist/agent/queues.js +44 -0
- package/dist/agent/queues.js.map +1 -0
- package/dist/agent/session-store.d.ts +21 -0
- package/dist/agent/session-store.js +96 -0
- package/dist/agent/session-store.js.map +1 -0
- package/dist/agent/templates.d.ts +5 -0
- package/dist/agent/templates.js +48 -0
- package/dist/agent/templates.js.map +1 -0
- package/dist/agent/tools.d.ts +25 -0
- package/dist/agent/tools.js +238 -0
- package/dist/agent/tools.js.map +1 -0
- package/dist/agent/types.d.ts +59 -0
- package/dist/agent/types.js +5 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/calendar/scheduler.d.ts +32 -0
- package/dist/calendar/scheduler.js +178 -0
- package/dist/calendar/scheduler.js.map +1 -0
- package/dist/calendar/store.d.ts +15 -0
- package/dist/calendar/store.js +50 -0
- package/dist/calendar/store.js.map +1 -0
- package/dist/calendar/types.d.ts +17 -0
- package/dist/calendar/types.js +5 -0
- package/dist/calendar/types.js.map +1 -0
- package/dist/chat/channel.d.ts +20 -0
- package/dist/chat/channel.js +84 -0
- package/dist/chat/channel.js.map +1 -0
- package/dist/chat/message-store.d.ts +18 -0
- package/dist/chat/message-store.js +82 -0
- package/dist/chat/message-store.js.map +1 -0
- package/dist/chat/router.d.ts +17 -0
- package/dist/chat/router.js +65 -0
- package/dist/chat/router.js.map +1 -0
- package/dist/chat/suggested-responses.d.ts +6 -0
- package/dist/chat/suggested-responses.js +99 -0
- package/dist/chat/suggested-responses.js.map +1 -0
- package/dist/chat/types.d.ts +28 -0
- package/dist/chat/types.js +5 -0
- package/dist/chat/types.js.map +1 -0
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/dispatch.d.ts +39 -0
- package/dist/commands/dispatch.js +1293 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/init.d.ts +49 -0
- package/dist/commands/init.js +315 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/parse-input.d.ts +5 -0
- package/dist/commands/parse-input.js +37 -0
- package/dist/commands/parse-input.js.map +1 -0
- package/dist/index.d.ts +6 -23
- package/dist/index.js +118 -50
- package/dist/index.js.map +1 -1
- package/dist/lib/client.js +1 -1
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/errors.js +1 -1
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/integrations.d.ts +23 -0
- package/dist/lib/integrations.js +25 -0
- package/dist/lib/integrations.js.map +1 -0
- package/dist/lib/nex-mcp-config.d.ts +14 -0
- package/dist/lib/nex-mcp-config.js +26 -0
- package/dist/lib/nex-mcp-config.js.map +1 -0
- package/dist/orchestration/budget.d.ts +32 -0
- package/dist/orchestration/budget.js +72 -0
- package/dist/orchestration/budget.js.map +1 -0
- package/dist/orchestration/executor.d.ts +59 -0
- package/dist/orchestration/executor.js +197 -0
- package/dist/orchestration/executor.js.map +1 -0
- package/dist/orchestration/router.d.ts +30 -0
- package/dist/orchestration/router.js +98 -0
- package/dist/orchestration/router.js.map +1 -0
- package/dist/orchestration/templates.d.ts +11 -0
- package/dist/orchestration/templates.js +99 -0
- package/dist/orchestration/templates.js.map +1 -0
- package/dist/orchestration/types.d.ts +58 -0
- package/dist/orchestration/types.js +7 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/plugin/shared.js +1 -1
- package/dist/plugin/shared.js.map +1 -1
- package/dist/tui/agent-colors.d.ts +19 -0
- package/dist/tui/agent-colors.js +34 -0
- package/dist/tui/agent-colors.js.map +1 -0
- package/dist/tui/app.d.ts +14 -0
- package/dist/tui/app.js +267 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/channel-colors.d.ts +16 -0
- package/dist/tui/channel-colors.js +43 -0
- package/dist/tui/channel-colors.js.map +1 -0
- package/dist/tui/components/agent-card.d.ts +11 -0
- package/dist/tui/components/agent-card.js +40 -0
- package/dist/tui/components/agent-card.js.map +1 -0
- package/dist/tui/components/banner.d.ts +44 -0
- package/dist/tui/components/banner.js +130 -0
- package/dist/tui/components/banner.js.map +1 -0
- package/dist/tui/components/channel-colors.d.ts +21 -0
- package/dist/tui/components/channel-colors.js +53 -0
- package/dist/tui/components/channel-colors.js.map +1 -0
- package/dist/tui/components/channel-message.d.ts +53 -0
- package/dist/tui/components/channel-message.js +66 -0
- package/dist/tui/components/channel-message.js.map +1 -0
- package/dist/tui/components/chat-input.d.ts +11 -0
- package/dist/tui/components/chat-input.js +19 -0
- package/dist/tui/components/chat-input.js.map +1 -0
- package/dist/tui/components/data-table.d.ts +11 -0
- package/dist/tui/components/data-table.js +47 -0
- package/dist/tui/components/data-table.js.map +1 -0
- package/dist/tui/components/error-box.d.ts +11 -0
- package/dist/tui/components/error-box.js +59 -0
- package/dist/tui/components/error-box.js.map +1 -0
- package/dist/tui/components/help-screen.d.ts +3 -0
- package/dist/tui/components/help-screen.js +63 -0
- package/dist/tui/components/help-screen.js.map +1 -0
- package/dist/tui/components/index.d.ts +17 -0
- package/dist/tui/components/index.js +10 -0
- package/dist/tui/components/index.js.map +1 -0
- package/dist/tui/components/inline-confirm.d.ts +14 -0
- package/dist/tui/components/inline-confirm.js +13 -0
- package/dist/tui/components/inline-confirm.js.map +1 -0
- package/dist/tui/components/inline-select.d.ts +21 -0
- package/dist/tui/components/inline-select.js +20 -0
- package/dist/tui/components/inline-select.js.map +1 -0
- package/dist/tui/components/markdown.d.ts +6 -0
- package/dist/tui/components/markdown.js +179 -0
- package/dist/tui/components/markdown.js.map +1 -0
- package/dist/tui/components/mention-autocomplete.d.ts +77 -0
- package/dist/tui/components/mention-autocomplete.js +235 -0
- package/dist/tui/components/mention-autocomplete.js.map +1 -0
- package/dist/tui/components/message-list.d.ts +18 -0
- package/dist/tui/components/message-list.js +29 -0
- package/dist/tui/components/message-list.js.map +1 -0
- package/dist/tui/components/picker.d.ts +16 -0
- package/dist/tui/components/picker.js +32 -0
- package/dist/tui/components/picker.js.map +1 -0
- package/dist/tui/components/progress-steps.d.ts +13 -0
- package/dist/tui/components/progress-steps.js +21 -0
- package/dist/tui/components/progress-steps.js.map +1 -0
- package/dist/tui/components/slack/compose.d.ts +27 -0
- package/dist/tui/components/slack/compose.js +123 -0
- package/dist/tui/components/slack/compose.js.map +1 -0
- package/dist/tui/components/slack/layout.d.ts +36 -0
- package/dist/tui/components/slack/layout.js +96 -0
- package/dist/tui/components/slack/layout.js.map +1 -0
- package/dist/tui/components/slack/messages.d.ts +72 -0
- package/dist/tui/components/slack/messages.js +177 -0
- package/dist/tui/components/slack/messages.js.map +1 -0
- package/dist/tui/components/slack/quick-switcher.d.ts +33 -0
- package/dist/tui/components/slack/quick-switcher.js +98 -0
- package/dist/tui/components/slack/quick-switcher.js.map +1 -0
- package/dist/tui/components/slack/sidebar-types.d.ts +65 -0
- package/dist/tui/components/slack/sidebar-types.js +7 -0
- package/dist/tui/components/slack/sidebar-types.js.map +1 -0
- package/dist/tui/components/slack/sidebar.d.ts +46 -0
- package/dist/tui/components/slack/sidebar.js +52 -0
- package/dist/tui/components/slack/sidebar.js.map +1 -0
- package/dist/tui/components/slack/thread-panel.d.ts +45 -0
- package/dist/tui/components/slack/thread-panel.js +47 -0
- package/dist/tui/components/slack/thread-panel.js.map +1 -0
- package/dist/tui/components/slash-autocomplete.d.ts +81 -0
- package/dist/tui/components/slash-autocomplete.js +218 -0
- package/dist/tui/components/slash-autocomplete.js.map +1 -0
- package/dist/tui/components/spinner.d.ts +17 -0
- package/dist/tui/components/spinner.js +30 -0
- package/dist/tui/components/spinner.js.map +1 -0
- package/dist/tui/components/status-bar.d.ts +23 -0
- package/dist/tui/components/status-bar.js +55 -0
- package/dist/tui/components/status-bar.js.map +1 -0
- package/dist/tui/components/success-box.d.ts +7 -0
- package/dist/tui/components/success-box.js +10 -0
- package/dist/tui/components/success-box.js.map +1 -0
- package/dist/tui/components/tool-indicator.d.ts +12 -0
- package/dist/tui/components/tool-indicator.js +18 -0
- package/dist/tui/components/tool-indicator.js.map +1 -0
- package/dist/tui/components/viewport.d.ts +9 -0
- package/dist/tui/components/viewport.js +24 -0
- package/dist/tui/components/viewport.js.map +1 -0
- package/dist/tui/generative/bindings.d.ts +27 -0
- package/dist/tui/generative/bindings.js +152 -0
- package/dist/tui/generative/bindings.js.map +1 -0
- package/dist/tui/generative/registry.d.ts +19 -0
- package/dist/tui/generative/registry.js +31 -0
- package/dist/tui/generative/registry.js.map +1 -0
- package/dist/tui/generative/renderer.d.ts +24 -0
- package/dist/tui/generative/renderer.js +160 -0
- package/dist/tui/generative/renderer.js.map +1 -0
- package/dist/tui/generative/types.d.ts +68 -0
- package/dist/tui/generative/types.js +7 -0
- package/dist/tui/generative/types.js.map +1 -0
- package/dist/tui/hooks/use-cancellable.d.ts +28 -0
- package/dist/tui/hooks/use-cancellable.js +51 -0
- package/dist/tui/hooks/use-cancellable.js.map +1 -0
- package/dist/tui/hooks/use-streaming.d.ts +44 -0
- package/dist/tui/hooks/use-streaming.js +105 -0
- package/dist/tui/hooks/use-streaming.js.map +1 -0
- package/dist/tui/index.d.ts +4 -0
- package/dist/tui/index.js +7 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/keybindings.d.ts +25 -0
- package/dist/tui/keybindings.js +277 -0
- package/dist/tui/keybindings.js.map +1 -0
- package/dist/tui/register-views.d.ts +8 -0
- package/dist/tui/register-views.js +116 -0
- package/dist/tui/register-views.js.map +1 -0
- package/dist/tui/router.d.ts +29 -0
- package/dist/tui/router.js +87 -0
- package/dist/tui/router.js.map +1 -0
- package/dist/tui/services/agent-service.d.ts +58 -0
- package/dist/tui/services/agent-service.js +197 -0
- package/dist/tui/services/agent-service.js.map +1 -0
- package/dist/tui/services/calendar-service.d.ts +31 -0
- package/dist/tui/services/calendar-service.js +133 -0
- package/dist/tui/services/calendar-service.js.map +1 -0
- package/dist/tui/services/chat-service.d.ts +28 -0
- package/dist/tui/services/chat-service.js +91 -0
- package/dist/tui/services/chat-service.js.map +1 -0
- package/dist/tui/services/orchestration-service.d.ts +42 -0
- package/dist/tui/services/orchestration-service.js +153 -0
- package/dist/tui/services/orchestration-service.js.map +1 -0
- package/dist/tui/slash-commands.d.ts +106 -0
- package/dist/tui/slash-commands.js +1421 -0
- package/dist/tui/slash-commands.js.map +1 -0
- package/dist/tui/store.d.ts +96 -0
- package/dist/tui/store.js +120 -0
- package/dist/tui/store.js.map +1 -0
- package/dist/tui/theme.d.ts +40 -0
- package/dist/tui/theme.js +39 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/tui-context.d.ts +22 -0
- package/dist/tui/tui-context.js +17 -0
- package/dist/tui/tui-context.js.map +1 -0
- package/dist/tui/views/agent-list.d.ts +8 -0
- package/dist/tui/views/agent-list.js +11 -0
- package/dist/tui/views/agent-list.js.map +1 -0
- package/dist/tui/views/ask-chat.d.ts +9 -0
- package/dist/tui/views/ask-chat.js +40 -0
- package/dist/tui/views/ask-chat.js.map +1 -0
- package/dist/tui/views/calendar.d.ts +15 -0
- package/dist/tui/views/calendar.js +29 -0
- package/dist/tui/views/calendar.js.map +1 -0
- package/dist/tui/views/chat.d.ts +18 -0
- package/dist/tui/views/chat.js +28 -0
- package/dist/tui/views/chat.js.map +1 -0
- package/dist/tui/views/generative.d.ts +14 -0
- package/dist/tui/views/generative.js +37 -0
- package/dist/tui/views/generative.js.map +1 -0
- package/dist/tui/views/help.d.ts +6 -0
- package/dist/tui/views/help.js +9 -0
- package/dist/tui/views/help.js.map +1 -0
- package/dist/tui/views/home-screen.d.ts +67 -0
- package/dist/tui/views/home-screen.js +192 -0
- package/dist/tui/views/home-screen.js.map +1 -0
- package/dist/tui/views/home.d.ts +33 -0
- package/dist/tui/views/home.js +60 -0
- package/dist/tui/views/home.js.map +1 -0
- package/dist/tui/views/index.d.ts +20 -0
- package/dist/tui/views/index.js +11 -0
- package/dist/tui/views/index.js.map +1 -0
- package/dist/tui/views/insights.d.ts +19 -0
- package/dist/tui/views/insights.js +46 -0
- package/dist/tui/views/insights.js.map +1 -0
- package/dist/tui/views/orchestration.d.ts +18 -0
- package/dist/tui/views/orchestration.js +73 -0
- package/dist/tui/views/orchestration.js.map +1 -0
- package/dist/tui/views/record-detail.d.ts +10 -0
- package/dist/tui/views/record-detail.js +22 -0
- package/dist/tui/views/record-detail.js.map +1 -0
- package/dist/tui/views/record-list.d.ts +15 -0
- package/dist/tui/views/record-list.js +22 -0
- package/dist/tui/views/record-list.js.map +1 -0
- package/dist/tui/views/slack-channel-header.d.ts +15 -0
- package/dist/tui/views/slack-channel-header.js +16 -0
- package/dist/tui/views/slack-channel-header.js.map +1 -0
- package/dist/tui/views/slack-home.d.ts +21 -0
- package/dist/tui/views/slack-home.js +572 -0
- package/dist/tui/views/slack-home.js.map +1 -0
- package/dist/tui/views/task-board.d.ts +21 -0
- package/dist/tui/views/task-board.js +33 -0
- package/dist/tui/views/task-board.js.map +1 -0
- package/dist/tui/views/timeline.d.ts +17 -0
- package/dist/tui/views/timeline.js +24 -0
- package/dist/tui/views/timeline.js.map +1 -0
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nex: Organizational Context & Memory Layer for AI agents
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@nex-ai/nex)
|
|
4
4
|
[](https://github.com/nex-crm/nex-as-a-skill)
|
|
5
|
+
[](https://discord.gg/gjSySC3PzV)
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Give any AI agent persistent memory & organizational context. One knowledge graph, every agent.
|
|
8
|
+
|
|
9
|
+
Tell something to OpenClaw. Ask about it in Claude Code. Reference it from Cursor. Context follows you across tools — no copy-pasting, no re-explaining, no lost context.
|
|
10
|
+
|
|
11
|
+
<a href="https://discord.gg/gjSySC3PzV"><img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Join our Discord" /></a>
|
|
12
|
+
|
|
13
|
+
Talk to the team, share feedback, and connect with other developers building AI agents with Nex.
|
|
7
14
|
|
|
8
15
|
**GitHub**: [github.com/nex-crm/nex-as-a-skill](https://github.com/nex-crm/nex-as-a-skill)
|
|
9
16
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selective insight adoption scoring and credibility tracking.
|
|
3
|
+
* Determines whether an agent should adopt, test, or reject a gossip insight.
|
|
4
|
+
*/
|
|
5
|
+
import type { GossipInsight } from './gossip.js';
|
|
6
|
+
export interface AdoptionScore {
|
|
7
|
+
sourceCredibility: number;
|
|
8
|
+
semanticRelevance: number;
|
|
9
|
+
temporalFreshness: number;
|
|
10
|
+
total: number;
|
|
11
|
+
decision: 'adopt' | 'test' | 'reject';
|
|
12
|
+
}
|
|
13
|
+
export declare function scoreInsight(insight: GossipInsight, _currentContext: string, sourceCredibility?: number): AdoptionScore;
|
|
14
|
+
export declare class CredibilityTracker {
|
|
15
|
+
private baseDir;
|
|
16
|
+
private filePath;
|
|
17
|
+
private data;
|
|
18
|
+
constructor(baseDir?: string);
|
|
19
|
+
private load;
|
|
20
|
+
private save;
|
|
21
|
+
getCredibility(agentSlug: string): number;
|
|
22
|
+
recordOutcome(agentSlug: string, success: boolean): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selective insight adoption scoring and credibility tracking.
|
|
3
|
+
* Determines whether an agent should adopt, test, or reject a gossip insight.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
const CREDIBILITY_WEIGHT = 0.4;
|
|
9
|
+
const RELEVANCE_WEIGHT = 0.4;
|
|
10
|
+
const FRESHNESS_WEIGHT = 0.2;
|
|
11
|
+
const ADOPT_THRESHOLD = 0.7;
|
|
12
|
+
const TEST_THRESHOLD = 0.4;
|
|
13
|
+
// Insights older than 7 days start losing freshness
|
|
14
|
+
const FRESHNESS_HALF_LIFE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
15
|
+
export function scoreInsight(insight, _currentContext, sourceCredibility) {
|
|
16
|
+
const credibility = sourceCredibility ?? 0.5;
|
|
17
|
+
const semanticRelevance = Math.max(0, Math.min(1, insight.relevance));
|
|
18
|
+
const age = Date.now() - insight.timestamp;
|
|
19
|
+
const temporalFreshness = Math.max(0, Math.exp(-age / FRESHNESS_HALF_LIFE_MS));
|
|
20
|
+
const total = credibility * CREDIBILITY_WEIGHT +
|
|
21
|
+
semanticRelevance * RELEVANCE_WEIGHT +
|
|
22
|
+
temporalFreshness * FRESHNESS_WEIGHT;
|
|
23
|
+
let decision;
|
|
24
|
+
if (total >= ADOPT_THRESHOLD) {
|
|
25
|
+
decision = 'adopt';
|
|
26
|
+
}
|
|
27
|
+
else if (total >= TEST_THRESHOLD) {
|
|
28
|
+
decision = 'test';
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
decision = 'reject';
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
sourceCredibility: credibility,
|
|
35
|
+
semanticRelevance,
|
|
36
|
+
temporalFreshness,
|
|
37
|
+
total,
|
|
38
|
+
decision,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export class CredibilityTracker {
|
|
42
|
+
baseDir;
|
|
43
|
+
filePath;
|
|
44
|
+
data;
|
|
45
|
+
constructor(baseDir) {
|
|
46
|
+
this.baseDir = baseDir ?? join(homedir(), '.nex-cli', 'credibility');
|
|
47
|
+
this.filePath = join(this.baseDir, 'scores.json');
|
|
48
|
+
this.data = this.load();
|
|
49
|
+
}
|
|
50
|
+
load() {
|
|
51
|
+
try {
|
|
52
|
+
if (!existsSync(this.filePath))
|
|
53
|
+
return {};
|
|
54
|
+
const raw = readFileSync(this.filePath, 'utf-8');
|
|
55
|
+
return JSON.parse(raw);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return {};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
save() {
|
|
62
|
+
mkdirSync(this.baseDir, { recursive: true });
|
|
63
|
+
writeFileSync(this.filePath, JSON.stringify(this.data, null, 2) + '\n', 'utf-8');
|
|
64
|
+
}
|
|
65
|
+
getCredibility(agentSlug) {
|
|
66
|
+
const record = this.data[agentSlug];
|
|
67
|
+
if (!record)
|
|
68
|
+
return 0.5;
|
|
69
|
+
const total = record.successes + record.failures;
|
|
70
|
+
if (total === 0)
|
|
71
|
+
return 0.5;
|
|
72
|
+
return record.successes / total;
|
|
73
|
+
}
|
|
74
|
+
recordOutcome(agentSlug, success) {
|
|
75
|
+
if (!this.data[agentSlug]) {
|
|
76
|
+
this.data[agentSlug] = { successes: 0, failures: 0 };
|
|
77
|
+
}
|
|
78
|
+
if (success) {
|
|
79
|
+
this.data[agentSlug].successes++;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.data[agentSlug].failures++;
|
|
83
|
+
}
|
|
84
|
+
this.save();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=adoption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adoption.js","sourceRoot":"","sources":["../../src/agent/adoption.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gossip layer for knowledge propagation between agents.
|
|
3
|
+
* Uses Nex Ask/Remember APIs to publish and query insights.
|
|
4
|
+
*/
|
|
5
|
+
import type { NexClient } from '../lib/client.js';
|
|
6
|
+
export interface GossipInsight {
|
|
7
|
+
content: string;
|
|
8
|
+
source: string;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
relevance: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class GossipLayer {
|
|
13
|
+
private client;
|
|
14
|
+
constructor(client: NexClient);
|
|
15
|
+
publish(agentSlug: string, insight: string, context?: string): Promise<string>;
|
|
16
|
+
query(agentSlug: string, topic: string): Promise<GossipInsight[]>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gossip layer for knowledge propagation between agents.
|
|
3
|
+
* Uses Nex Ask/Remember APIs to publish and query insights.
|
|
4
|
+
*/
|
|
5
|
+
export class GossipLayer {
|
|
6
|
+
client;
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
}
|
|
10
|
+
async publish(agentSlug, insight, context) {
|
|
11
|
+
const taggedContent = `[agent:${agentSlug}] ${insight}`;
|
|
12
|
+
const tags = ['gossip', `agent:${agentSlug}`];
|
|
13
|
+
if (context)
|
|
14
|
+
tags.push(`ctx:${context}`);
|
|
15
|
+
const result = await this.client.post('/remember', {
|
|
16
|
+
content: taggedContent,
|
|
17
|
+
tags,
|
|
18
|
+
});
|
|
19
|
+
return result.id ?? 'stored';
|
|
20
|
+
}
|
|
21
|
+
async query(agentSlug, topic) {
|
|
22
|
+
const result = await this.client.post('/search', {
|
|
23
|
+
query: `[gossip] ${topic}`,
|
|
24
|
+
limit: 10,
|
|
25
|
+
});
|
|
26
|
+
if (!result.results || !Array.isArray(result.results))
|
|
27
|
+
return [];
|
|
28
|
+
return result.results
|
|
29
|
+
.filter(r => {
|
|
30
|
+
// Exclude the querying agent's own insights
|
|
31
|
+
const content = r.content ?? '';
|
|
32
|
+
return !content.startsWith(`[agent:${agentSlug}]`);
|
|
33
|
+
})
|
|
34
|
+
.map(r => {
|
|
35
|
+
const content = r.content ?? '';
|
|
36
|
+
const sourceMatch = content.match(/^\[agent:([^\]]+)\]/);
|
|
37
|
+
const source = sourceMatch ? sourceMatch[1] : 'unknown';
|
|
38
|
+
const cleanContent = content.replace(/^\[agent:[^\]]+\]\s*/, '');
|
|
39
|
+
return {
|
|
40
|
+
content: cleanContent,
|
|
41
|
+
source,
|
|
42
|
+
timestamp: Date.now(),
|
|
43
|
+
relevance: r.score ?? 0,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=gossip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gossip.js","sourceRoot":"","sources":["../../src/agent/gossip.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,OAAO,WAAW;IACd,MAAM,CAAY;IAE1B,YAAY,MAAiB;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,OAAe,EAAE,OAAgB;QAChE,MAAM,aAAa,GAAG,UAAU,SAAS,KAAK,OAAO,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAC,CAAC;QAC9C,IAAI,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;QAEzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAkB,WAAW,EAAE;YAClE,OAAO,EAAE,aAAa;YACtB,IAAI;SACL,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,EAAE,IAAI,QAAQ,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAAiB,EAAE,KAAa;QAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAMlC,SAAS,EAAE;YACZ,KAAK,EAAE,YAAY,KAAK,EAAE;YAC1B,KAAK,EAAE,EAAE;SACV,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QAEjE,OAAO,MAAM,CAAC,OAAO;aAClB,MAAM,CAAC,CAAC,CAAC,EAAE;YACV,4CAA4C;YAC5C,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;YAChC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,SAAS,GAAG,CAAC,CAAC;QACrD,CAAC,CAAC;aACD,GAAG,CAAC,CAAC,CAAC,EAAE;YACP,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;YAChC,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACxD,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;YAEjE,OAAO;gBACL,OAAO,EAAE,YAAY;gBACrB,MAAM;gBACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,SAAS,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;aACxB,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC;CACF"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi-style state machine agent loop.
|
|
3
|
+
* Runs idle -> build_context -> stream_llm -> execute_tool -> done cycle.
|
|
4
|
+
* Mock streamFn used until real LLM integration.
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentConfig, AgentState, StreamFn } from './types.js';
|
|
7
|
+
import type { ToolRegistry } from './tools.js';
|
|
8
|
+
import type { AgentSessionStore } from './session-store.js';
|
|
9
|
+
import type { MessageQueues } from './queues.js';
|
|
10
|
+
import type { GossipLayer } from './gossip.js';
|
|
11
|
+
import type { CredibilityTracker } from './adoption.js';
|
|
12
|
+
type EventName = 'phase_change' | 'tool_call' | 'message' | 'error' | 'done';
|
|
13
|
+
type EventHandler = (...args: unknown[]) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Mock streamFn that simulates LLM responses.
|
|
16
|
+
* Returns a text response, optionally followed by a tool call if tools are available.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createMockStreamFn(): StreamFn;
|
|
19
|
+
export declare class AgentLoop {
|
|
20
|
+
private state;
|
|
21
|
+
private tools;
|
|
22
|
+
private sessions;
|
|
23
|
+
private queues;
|
|
24
|
+
private streamFn;
|
|
25
|
+
private gossipLayer;
|
|
26
|
+
private credibilityTracker;
|
|
27
|
+
private running;
|
|
28
|
+
private paused;
|
|
29
|
+
private eventHandlers;
|
|
30
|
+
private pendingToolCall;
|
|
31
|
+
private abortController;
|
|
32
|
+
/** Tracks whether the current task had any errors (tool failures, LLM errors). */
|
|
33
|
+
private taskHadError;
|
|
34
|
+
/** Insights collected during this execution cycle (from tool results, gossip publish calls). */
|
|
35
|
+
private collectedInsights;
|
|
36
|
+
constructor(config: AgentConfig, tools: ToolRegistry, sessions: AgentSessionStore, queues: MessageQueues, streamFn?: StreamFn, gossipLayer?: GossipLayer, credibilityTracker?: CredibilityTracker);
|
|
37
|
+
private setPhase;
|
|
38
|
+
private emit;
|
|
39
|
+
on(event: EventName, handler: EventHandler): void;
|
|
40
|
+
off(event: string, handler: EventHandler): void;
|
|
41
|
+
getState(): AgentState;
|
|
42
|
+
tick(): Promise<void>;
|
|
43
|
+
private buildContext;
|
|
44
|
+
/**
|
|
45
|
+
* Query the gossip layer, score each insight, and inject adopted/test insights
|
|
46
|
+
* into the session as system messages.
|
|
47
|
+
*/
|
|
48
|
+
private injectGossipInsights;
|
|
49
|
+
private streamLlm;
|
|
50
|
+
private executeTool;
|
|
51
|
+
private handleDone;
|
|
52
|
+
start(): void;
|
|
53
|
+
stop(): void;
|
|
54
|
+
pause(): void;
|
|
55
|
+
resume(): void;
|
|
56
|
+
/** Allow external code or tools to push insights for gossip publishing at done phase. */
|
|
57
|
+
addInsight(insight: string): void;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi-style state machine agent loop.
|
|
3
|
+
* Runs idle -> build_context -> stream_llm -> execute_tool -> done cycle.
|
|
4
|
+
* Mock streamFn used until real LLM integration.
|
|
5
|
+
*/
|
|
6
|
+
import { scoreInsight } from './adoption.js';
|
|
7
|
+
/**
|
|
8
|
+
* Mock streamFn that simulates LLM responses.
|
|
9
|
+
* Returns a text response, optionally followed by a tool call if tools are available.
|
|
10
|
+
*/
|
|
11
|
+
export function createMockStreamFn() {
|
|
12
|
+
return async function* mockStream(messages, tools) {
|
|
13
|
+
const lastMsg = messages[messages.length - 1];
|
|
14
|
+
const content = lastMsg?.content ?? '';
|
|
15
|
+
// If tools available, simulate a tool call for search-like queries
|
|
16
|
+
if (tools.length > 0 && content.toLowerCase().includes('search')) {
|
|
17
|
+
const searchTool = tools.find(t => t.name.includes('search'));
|
|
18
|
+
if (searchTool) {
|
|
19
|
+
yield {
|
|
20
|
+
type: 'tool_call',
|
|
21
|
+
toolName: searchTool.name,
|
|
22
|
+
toolParams: { query: content },
|
|
23
|
+
};
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
yield {
|
|
28
|
+
type: 'text',
|
|
29
|
+
content: `Processed: ${content}`,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export class AgentLoop {
|
|
34
|
+
state;
|
|
35
|
+
tools;
|
|
36
|
+
sessions;
|
|
37
|
+
queues;
|
|
38
|
+
streamFn;
|
|
39
|
+
gossipLayer;
|
|
40
|
+
credibilityTracker;
|
|
41
|
+
running = false;
|
|
42
|
+
paused = false;
|
|
43
|
+
eventHandlers = new Map();
|
|
44
|
+
pendingToolCall = null;
|
|
45
|
+
abortController = null;
|
|
46
|
+
/** Tracks whether the current task had any errors (tool failures, LLM errors). */
|
|
47
|
+
taskHadError = false;
|
|
48
|
+
/** Insights collected during this execution cycle (from tool results, gossip publish calls). */
|
|
49
|
+
collectedInsights = [];
|
|
50
|
+
constructor(config, tools, sessions, queues, streamFn, gossipLayer, credibilityTracker) {
|
|
51
|
+
this.tools = tools;
|
|
52
|
+
this.sessions = sessions;
|
|
53
|
+
this.queues = queues;
|
|
54
|
+
this.streamFn = streamFn ?? createMockStreamFn();
|
|
55
|
+
this.gossipLayer = gossipLayer ?? null;
|
|
56
|
+
this.credibilityTracker = credibilityTracker ?? null;
|
|
57
|
+
this.state = {
|
|
58
|
+
phase: 'idle',
|
|
59
|
+
config,
|
|
60
|
+
tokensUsed: 0,
|
|
61
|
+
costUsd: 0,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
setPhase(phase) {
|
|
65
|
+
const prev = this.state.phase;
|
|
66
|
+
this.state.phase = phase;
|
|
67
|
+
this.emit('phase_change', prev, phase);
|
|
68
|
+
}
|
|
69
|
+
emit(event, ...args) {
|
|
70
|
+
const handlers = this.eventHandlers.get(event);
|
|
71
|
+
if (handlers) {
|
|
72
|
+
for (const handler of handlers) {
|
|
73
|
+
try {
|
|
74
|
+
handler(...args);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// swallow handler errors
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
on(event, handler) {
|
|
83
|
+
let set = this.eventHandlers.get(event);
|
|
84
|
+
if (!set) {
|
|
85
|
+
set = new Set();
|
|
86
|
+
this.eventHandlers.set(event, set);
|
|
87
|
+
}
|
|
88
|
+
set.add(handler);
|
|
89
|
+
}
|
|
90
|
+
off(event, handler) {
|
|
91
|
+
const set = this.eventHandlers.get(event);
|
|
92
|
+
if (set) {
|
|
93
|
+
set.delete(handler);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
getState() {
|
|
97
|
+
return { ...this.state };
|
|
98
|
+
}
|
|
99
|
+
async tick() {
|
|
100
|
+
if (this.paused)
|
|
101
|
+
return;
|
|
102
|
+
// Check for steer interrupts
|
|
103
|
+
const steerMsg = this.queues.drainSteer(this.state.config.slug);
|
|
104
|
+
if (steerMsg) {
|
|
105
|
+
if (this.state.sessionId) {
|
|
106
|
+
this.sessions.append(this.state.sessionId, {
|
|
107
|
+
type: 'system',
|
|
108
|
+
content: `[STEER] ${steerMsg}`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
switch (this.state.phase) {
|
|
113
|
+
case 'idle':
|
|
114
|
+
await this.buildContext();
|
|
115
|
+
break;
|
|
116
|
+
case 'build_context':
|
|
117
|
+
await this.streamLlm();
|
|
118
|
+
break;
|
|
119
|
+
case 'stream_llm':
|
|
120
|
+
if (this.pendingToolCall) {
|
|
121
|
+
await this.executeTool();
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
await this.handleDone();
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
case 'execute_tool':
|
|
128
|
+
await this.streamLlm();
|
|
129
|
+
break;
|
|
130
|
+
case 'done':
|
|
131
|
+
await this.handleDone();
|
|
132
|
+
break;
|
|
133
|
+
case 'error':
|
|
134
|
+
// Stay in error until reset
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async buildContext() {
|
|
139
|
+
this.setPhase('build_context');
|
|
140
|
+
this.taskHadError = false;
|
|
141
|
+
this.collectedInsights = [];
|
|
142
|
+
if (!this.state.sessionId) {
|
|
143
|
+
this.state.sessionId = this.sessions.create(this.state.config.slug);
|
|
144
|
+
}
|
|
145
|
+
// Inject follow-up messages as context
|
|
146
|
+
const followUp = this.queues.drainFollowUp(this.state.config.slug);
|
|
147
|
+
if (followUp) {
|
|
148
|
+
this.sessions.append(this.state.sessionId, {
|
|
149
|
+
type: 'user',
|
|
150
|
+
content: followUp,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// Query gossip layer for relevant insights from other agents
|
|
154
|
+
if (this.gossipLayer) {
|
|
155
|
+
await this.injectGossipInsights();
|
|
156
|
+
}
|
|
157
|
+
this.setPhase('build_context');
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Query the gossip layer, score each insight, and inject adopted/test insights
|
|
161
|
+
* into the session as system messages.
|
|
162
|
+
*/
|
|
163
|
+
async injectGossipInsights() {
|
|
164
|
+
if (!this.gossipLayer || !this.state.sessionId)
|
|
165
|
+
return;
|
|
166
|
+
const topic = this.state.config.expertise.join(', ');
|
|
167
|
+
let insights;
|
|
168
|
+
try {
|
|
169
|
+
insights = await this.gossipLayer.query(this.state.config.slug, topic);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Gossip query failure is non-fatal; continue without insights
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (insights.length === 0)
|
|
176
|
+
return;
|
|
177
|
+
const adopted = [];
|
|
178
|
+
const experimental = [];
|
|
179
|
+
for (const insight of insights) {
|
|
180
|
+
const sourceCredibility = this.credibilityTracker
|
|
181
|
+
? this.credibilityTracker.getCredibility(insight.source)
|
|
182
|
+
: undefined;
|
|
183
|
+
const score = scoreInsight(insight, topic, sourceCredibility);
|
|
184
|
+
if (score.decision === 'adopt') {
|
|
185
|
+
adopted.push({ insight, score: score.total });
|
|
186
|
+
}
|
|
187
|
+
else if (score.decision === 'test') {
|
|
188
|
+
experimental.push({ insight, score: score.total });
|
|
189
|
+
}
|
|
190
|
+
// 'reject' insights are silently dropped
|
|
191
|
+
}
|
|
192
|
+
if (adopted.length > 0) {
|
|
193
|
+
const lines = adopted.map(a => `- [${a.insight.source}] (score ${a.score.toFixed(2)}): ${a.insight.content}`);
|
|
194
|
+
this.sessions.append(this.state.sessionId, {
|
|
195
|
+
type: 'system',
|
|
196
|
+
content: `[GOSSIP:ADOPTED] Trusted insights from other agents:\n${lines.join('\n')}`,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (experimental.length > 0) {
|
|
200
|
+
const lines = experimental.map(e => `- [${e.insight.source}] (score ${e.score.toFixed(2)}): ${e.insight.content}`);
|
|
201
|
+
this.sessions.append(this.state.sessionId, {
|
|
202
|
+
type: 'system',
|
|
203
|
+
content: `[GOSSIP:TEST] Consider verifying these insights experimentally:\n${lines.join('\n')}`,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async streamLlm() {
|
|
208
|
+
this.setPhase('stream_llm');
|
|
209
|
+
const history = this.state.sessionId
|
|
210
|
+
? this.sessions.getHistory(this.state.sessionId)
|
|
211
|
+
: [];
|
|
212
|
+
const messages = history.map(e => ({
|
|
213
|
+
role: e.type === 'user' ? 'user' : 'assistant',
|
|
214
|
+
content: e.content,
|
|
215
|
+
}));
|
|
216
|
+
if (messages.length === 0) {
|
|
217
|
+
messages.push({
|
|
218
|
+
role: 'system',
|
|
219
|
+
content: `You are ${this.state.config.name}. Expertise: ${this.state.config.expertise.join(', ')}.${this.state.config.personality ? ' ' + this.state.config.personality : ''}`,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
this.abortController = new AbortController();
|
|
223
|
+
const availableTools = this.tools.list().filter(t => !this.state.config.tools || this.state.config.tools.includes(t.name));
|
|
224
|
+
let fullText = '';
|
|
225
|
+
this.pendingToolCall = null;
|
|
226
|
+
try {
|
|
227
|
+
for await (const chunk of this.streamFn(messages, availableTools)) {
|
|
228
|
+
if (this.abortController.signal.aborted)
|
|
229
|
+
break;
|
|
230
|
+
if (chunk.type === 'text' && chunk.content) {
|
|
231
|
+
fullText += chunk.content;
|
|
232
|
+
this.emit('message', chunk.content);
|
|
233
|
+
}
|
|
234
|
+
else if (chunk.type === 'tool_call' && chunk.toolName) {
|
|
235
|
+
this.pendingToolCall = {
|
|
236
|
+
toolName: chunk.toolName,
|
|
237
|
+
params: chunk.toolParams ?? {},
|
|
238
|
+
startedAt: Date.now(),
|
|
239
|
+
};
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
this.state.error = err instanceof Error ? err.message : String(err);
|
|
246
|
+
this.setPhase('error');
|
|
247
|
+
this.emit('error', this.state.error);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (fullText && this.state.sessionId) {
|
|
251
|
+
this.sessions.append(this.state.sessionId, {
|
|
252
|
+
type: 'assistant',
|
|
253
|
+
content: fullText,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async executeTool() {
|
|
258
|
+
if (!this.pendingToolCall) {
|
|
259
|
+
this.setPhase('stream_llm');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
this.setPhase('execute_tool');
|
|
263
|
+
const call = this.pendingToolCall;
|
|
264
|
+
this.emit('tool_call', call.toolName, call.params);
|
|
265
|
+
const tool = this.tools.get(call.toolName);
|
|
266
|
+
if (!tool) {
|
|
267
|
+
call.error = `Unknown tool: ${call.toolName}`;
|
|
268
|
+
call.completedAt = Date.now();
|
|
269
|
+
this.taskHadError = true;
|
|
270
|
+
if (this.state.sessionId) {
|
|
271
|
+
this.sessions.append(this.state.sessionId, {
|
|
272
|
+
type: 'tool_result',
|
|
273
|
+
content: call.error,
|
|
274
|
+
metadata: { toolName: call.toolName, error: true },
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
this.pendingToolCall = null;
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const validation = this.tools.validate(call.toolName, call.params);
|
|
281
|
+
if (!validation.valid) {
|
|
282
|
+
call.error = `Validation failed: ${validation.errors?.join(', ')}`;
|
|
283
|
+
call.completedAt = Date.now();
|
|
284
|
+
this.taskHadError = true;
|
|
285
|
+
if (this.state.sessionId) {
|
|
286
|
+
this.sessions.append(this.state.sessionId, {
|
|
287
|
+
type: 'tool_result',
|
|
288
|
+
content: call.error,
|
|
289
|
+
metadata: { toolName: call.toolName, error: true },
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
this.pendingToolCall = null;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (this.state.sessionId) {
|
|
296
|
+
this.sessions.append(this.state.sessionId, {
|
|
297
|
+
type: 'tool_call',
|
|
298
|
+
content: JSON.stringify({ tool: call.toolName, params: call.params }),
|
|
299
|
+
metadata: { toolName: call.toolName },
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
const controller = this.abortController ?? new AbortController();
|
|
303
|
+
try {
|
|
304
|
+
call.result = await tool.execute(call.params, controller.signal, (partial) => {
|
|
305
|
+
this.emit('message', partial);
|
|
306
|
+
});
|
|
307
|
+
call.completedAt = Date.now();
|
|
308
|
+
if (this.state.sessionId) {
|
|
309
|
+
this.sessions.append(this.state.sessionId, {
|
|
310
|
+
type: 'tool_result',
|
|
311
|
+
content: call.result,
|
|
312
|
+
metadata: { toolName: call.toolName },
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
call.error = err instanceof Error ? err.message : String(err);
|
|
318
|
+
call.completedAt = Date.now();
|
|
319
|
+
this.taskHadError = true;
|
|
320
|
+
if (this.state.sessionId) {
|
|
321
|
+
this.sessions.append(this.state.sessionId, {
|
|
322
|
+
type: 'tool_result',
|
|
323
|
+
content: call.error,
|
|
324
|
+
metadata: { toolName: call.toolName, error: true },
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Collect insight from gossip_publish tool calls
|
|
329
|
+
if (call.toolName === 'nex_gossip_publish' && call.result && !call.error) {
|
|
330
|
+
const insight = call.params.insight;
|
|
331
|
+
if (typeof insight === 'string') {
|
|
332
|
+
this.collectedInsights.push(insight);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
this.pendingToolCall = null;
|
|
336
|
+
}
|
|
337
|
+
async handleDone() {
|
|
338
|
+
// Check if there's more work from queues
|
|
339
|
+
if (this.queues.hasSteer(this.state.config.slug) || this.queues.hasFollowUp(this.state.config.slug)) {
|
|
340
|
+
this.setPhase('idle');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// Publish any collected insights via gossip layer
|
|
344
|
+
if (this.gossipLayer && this.collectedInsights.length > 0) {
|
|
345
|
+
for (const insight of this.collectedInsights) {
|
|
346
|
+
try {
|
|
347
|
+
await this.gossipLayer.publish(this.state.config.slug, insight);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// Gossip publish failure is non-fatal
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
this.collectedInsights = [];
|
|
354
|
+
}
|
|
355
|
+
// Update credibility based on task outcome
|
|
356
|
+
if (this.credibilityTracker) {
|
|
357
|
+
this.credibilityTracker.recordOutcome(this.state.config.slug, !this.taskHadError);
|
|
358
|
+
}
|
|
359
|
+
this.setPhase('done');
|
|
360
|
+
this.state.lastHeartbeat = Date.now();
|
|
361
|
+
this.emit('done');
|
|
362
|
+
}
|
|
363
|
+
start() {
|
|
364
|
+
this.running = true;
|
|
365
|
+
this.paused = false;
|
|
366
|
+
if (this.state.phase === 'done' || this.state.phase === 'error') {
|
|
367
|
+
this.setPhase('idle');
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
stop() {
|
|
371
|
+
this.running = false;
|
|
372
|
+
this.paused = false;
|
|
373
|
+
if (this.abortController) {
|
|
374
|
+
this.abortController.abort();
|
|
375
|
+
}
|
|
376
|
+
this.setPhase('done');
|
|
377
|
+
}
|
|
378
|
+
pause() {
|
|
379
|
+
this.paused = true;
|
|
380
|
+
}
|
|
381
|
+
resume() {
|
|
382
|
+
this.paused = false;
|
|
383
|
+
}
|
|
384
|
+
/** Allow external code or tools to push insights for gossip publishing at done phase. */
|
|
385
|
+
addInsight(insight) {
|
|
386
|
+
this.collectedInsights.push(insight);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=loop.js.map
|