nolo-cli 0.1.41 → 0.1.43
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 +27 -12
- package/agent-runtime/agentThread.ts +222 -0
- package/agent-runtime/agentThreadAdmission.ts +74 -0
- package/agent-runtime/dialogWritePlan.ts +42 -0
- package/agent-runtime/hostAdapter.ts +1 -0
- package/agent-runtime/index.ts +43 -0
- package/agent-runtime/localLoop.ts +31 -2
- package/agent-runtime/localToolPolicy.ts +1 -0
- package/agent-runtime/localWorkspaceTools.ts +1258 -78
- package/agent-runtime/noloWorkspaceTools.ts +20 -1
- package/agent-runtime/runtimeToolPolicy.ts +1 -5
- package/agent-runtime/runtimeToolSurface.ts +1 -0
- package/agentAliases.ts +29 -9
- package/agentInternalCommandEntries.ts +11 -3
- package/agentMachineCommands.ts +1 -0
- package/agentRecordCommands.ts +2 -2
- package/agentRecordHelpers.ts +59 -6
- package/agentRunCommand.ts +84 -19
- package/ai/agent/buildSystemPrompt.ts +14 -0
- package/ai/agent/cliExecutor.ts +202 -43
- package/ai/agent/createAgentSchema.ts +2 -2
- package/ai/agent/liveAudioModel.ts +1 -1
- package/ai/agent/streamAgentChatTurn.ts +154 -20
- package/ai/agent/streamAgentChatTurnUtils.ts +63 -0
- package/ai/ai.locale.ts +70 -0
- package/ai/chat/inlineImageUrlsForCustomProvider.ts +7 -2
- package/ai/chat/sendOpenAICompletionsRequest.ts +25 -1
- package/ai/llm/kimi.ts +0 -1
- package/ai/llm/openrouterModels.ts +27 -2
- package/ai/memory/policy.ts +49 -0
- package/ai/memory/queryShared.ts +10 -4
- package/ai/memory/recentRelationshipRecap.ts +4 -0
- package/ai/memory/remember.ts +48 -104
- package/ai/memory/scope.ts +74 -0
- package/ai/memory/types.ts +6 -0
- package/ai/memory/understanding.ts +10 -18
- package/ai/policy/runtimePolicy.ts +95 -23
- package/ai/tools/agent/agentTools.ts +0 -21
- package/ai/tools/agent/startAgentDialogTool.ts +2 -1
- package/ai/tools/index.ts +2 -20
- package/ai/tools/prepareTools.ts +171 -1
- package/ai/tools/readXhsProfileTool.ts +80 -69
- package/ai/tools/table/createTableTool.ts +11 -0
- package/ai/tools/toolPacks.ts +19 -0
- package/ai/types.ts +3 -0
- package/app/favorite/deletedFavoriteProjection.ts +31 -0
- package/app/hooks/deleteDbKey.ts +24 -3
- package/app/i18n/translations/interface.locale.ts +48 -16
- package/app/types/appSummary.ts +4 -0
- package/app/utils/desktopAgentRuntimeTurnClient.ts +2 -0
- package/auth/adminPermissions.ts +64 -4
- package/auth/routes.ts +5 -0
- package/chat/chat.locale.ts +4 -0
- package/chat/dialog/actions/handleSendMessageAction.ts +7 -2
- package/chat/dialog/dialogAttachmentCleanup.ts +135 -0
- package/chat/dialog/dialogSlice.ts +117 -4
- package/chat/messages/activityCompletion.ts +97 -0
- package/chat/messages/imagePayloadPersistence.ts +22 -0
- package/chat/messages/messageContent.ts +20 -16
- package/chat/messages/messageSlice.ts +20 -1
- package/chat/messages/toolThunks.ts +32 -11
- package/chat/messages/types.ts +8 -1
- package/chat/messages/web/toolDisplayName.ts +686 -0
- package/cli/agentAliases.ts +29 -9
- package/cli/agentInternalCommandEntries.ts +11 -3
- package/cli/agentMachineCommands.ts +1 -0
- package/cli/agentRecordCommands.ts +2 -2
- package/cli/agentRecordHelpers.ts +59 -6
- package/cli/agentRunCommand.ts +84 -19
- package/cli/client/agentRun.ts +65 -253
- package/cli/client/localRuntimeAdapter.ts +179 -53
- package/cli/commandRegistry.ts +7 -4
- package/cli/dialogAttachmentCleanup.ts +151 -0
- package/cli/dialogCommands.ts +163 -61
- package/cli/dialogInternalCommandEntries.ts +1 -1
- package/cli/docCreateCommands.ts +345 -0
- package/cli/docInternalCommandEntries.ts +11 -0
- package/cli/docPageHelpers.ts +80 -0
- package/cli/docSkillHelpers.ts +67 -0
- package/cli/docSpaceHelpers.ts +46 -0
- package/cli/internalCommandEntries.ts +4 -0
- package/cli/machineCommands.ts +18 -34
- package/cli/memoryCommands.ts +253 -0
- package/cli/memoryInternalCommandEntries.ts +9 -0
- package/cli/qoderUsageProbe.ts +252 -0
- package/cli/scriptCommandEntries.ts +0 -3
- package/cli/secretScan.ts +31 -0
- package/cli/tableCommands.ts +248 -13
- package/cli/workflowInternalCommandEntries.ts +2 -3
- package/client/agentRun.test.ts +68 -84
- package/client/agentRun.ts +65 -253
- package/client/localRuntimeAdapter.test.ts +505 -74
- package/client/localRuntimeAdapter.ts +179 -53
- package/commandRegistry.ts +7 -4
- package/connector-experimental/capabilities.ts +10 -9
- package/create/space/sidebarVisibleTypes.ts +19 -0
- package/dialogAttachmentCleanup.ts +151 -0
- package/dialogCommands.ts +163 -61
- package/dialogInternalCommandEntries.ts +1 -1
- package/docCreateCommands.ts +345 -0
- package/docInternalCommandEntries.ts +11 -0
- package/docPageHelpers.ts +80 -0
- package/docSkillHelpers.ts +67 -0
- package/docSpaceHelpers.ts +46 -0
- package/integrations/google/models.ts +4 -4
- package/integrations/openai/generateOpenAIRequestBody.ts +0 -3
- package/integrations/xhs-reader/types.ts +36 -3
- package/integrations/xhs-reader/url.ts +24 -1
- package/internalCommandEntries.ts +4 -0
- package/machineCommands.ts +18 -34
- package/memoryCommands.ts +253 -0
- package/memoryInternalCommandEntries.ts +9 -0
- package/package.json +141 -114
- package/qoderUsageProbe.ts +252 -0
- package/render/contentIcon/types.ts +167 -0
- package/render/page/docSlice.ts +30 -3
- package/render/page/types.ts +2 -0
- package/render/table/createTableAction.ts +4 -0
- package/render/table/tableSlice.ts +61 -0
- package/render/table/types.ts +10 -0
- package/scriptCommandEntries.ts +0 -3
- package/secretScan.ts +31 -0
- package/server/handlers/agentRun/types.ts +24 -23
- package/tableCommands.ts +248 -13
- package/workflowInternalCommandEntries.ts +2 -3
- package/ai/tools/agent/taskRunTool.ts +0 -112
- package/cli/client/taskRunPrompt.ts +0 -27
- package/cli/taskRunCommand.ts +0 -265
- package/client/taskRunPrompt.ts +0 -27
- package/integrations/xhs-reader/analyze/profileAnalyzer.ts +0 -205
- package/integrations/xhs-reader/backends/playwrightProfileCollector.ts +0 -624
- package/integrations/xhs-reader/bridge/readXhsProfileWithBridge.ts +0 -227
- package/integrations/xhs-reader/client/xhsWebApiClient.ts +0 -229
- package/integrations/xhs-reader/normalize.ts +0 -390
- package/integrations/xhs-reader/orchestrator.ts +0 -178
- package/taskRunCommand.ts +0 -265
package/README.md
CHANGED
|
@@ -37,6 +37,9 @@ nolo
|
|
|
37
37
|
nolo doctor
|
|
38
38
|
nolo --version
|
|
39
39
|
|
|
40
|
+
# no Nolo login required: runs the local Codex CLI in the current directory
|
|
41
|
+
nolo run "review this repository"
|
|
42
|
+
|
|
40
43
|
# update later from your shell
|
|
41
44
|
nolo update
|
|
42
45
|
```
|
|
@@ -48,7 +51,14 @@ Inside the TUI, run:
|
|
|
48
51
|
```
|
|
49
52
|
|
|
50
53
|
The npm package expects Bun to be available because the executable is a Bun
|
|
51
|
-
TypeScript script.
|
|
54
|
+
TypeScript script.
|
|
55
|
+
|
|
56
|
+
For local maintainer workflows, `nolo run "..."` does not require a Nolo
|
|
57
|
+
account. It resolves to the built-in `local-codex` agent, runs in the current
|
|
58
|
+
working directory, and uses the local Codex CLI installation. This is intended
|
|
59
|
+
for repository-local review, triage, and release-check tasks.
|
|
60
|
+
|
|
61
|
+
Remote Nolo records and synced workflows still require a token:
|
|
52
62
|
|
|
53
63
|
```bash
|
|
54
64
|
NOLO_SERVER=https://nolo.chat AUTH_TOKEN=<token> nolo
|
|
@@ -87,6 +97,8 @@ nolo --help
|
|
|
87
97
|
nolo doctor
|
|
88
98
|
nolo update
|
|
89
99
|
nolo
|
|
100
|
+
nolo run "review this repository"
|
|
101
|
+
nolo chat "triage the failing tests"
|
|
90
102
|
nolo chat
|
|
91
103
|
nolo connect
|
|
92
104
|
nolo connect --watch
|
|
@@ -107,8 +119,8 @@ nolo chat --agent agent-pub-01APPBUILDER00000001YAII3I --msg "你好"
|
|
|
107
119
|
|
|
108
120
|
For document creation, prefer the CLI over direct scripts. Use `nolo doc create`
|
|
109
121
|
for ordinary pages and `nolo skill-doc create` for skill-backed pages. Both
|
|
110
|
-
support `--sync`, `--dry-run`, `--json`, and `--allow-secrets
|
|
111
|
-
the
|
|
122
|
+
support `--sync`, `--dry-run`, `--json`, and `--allow-secrets`, and both write
|
|
123
|
+
for the current auth token user rather than a demo bootstrap user.
|
|
112
124
|
|
|
113
125
|
Experimental machine connector commands:
|
|
114
126
|
|
|
@@ -176,7 +188,7 @@ nolo agent list --space <space>
|
|
|
176
188
|
nolo dialog list
|
|
177
189
|
nolo dialog list --space <space>
|
|
178
190
|
nolo dialog read <dialog>
|
|
179
|
-
nolo dialog delete <dialog
|
|
191
|
+
nolo dialog delete <dialog...> --yes
|
|
180
192
|
nolo doc list --agent <agent>
|
|
181
193
|
nolo table query --table meta-0e95801d90-NOLOTASKBOARD --limit 20
|
|
182
194
|
nolo table query --table meta-0e95801d90-NOLOTASKBOARD --columns '["title","status","owner","priority","codeStatus"]' --no-base-fields --output items
|
|
@@ -208,14 +220,17 @@ commands instead of ad hoc scripts:
|
|
|
208
220
|
updates such as `--model`, `--cli-provider`, `--api-source`, and repeated
|
|
209
221
|
`--field key=value`.
|
|
210
222
|
|
|
211
|
-
Account ownership matters for private agent maintenance.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
as
|
|
217
|
-
|
|
218
|
-
|
|
223
|
+
Account ownership matters for private agent maintenance. Default new tests,
|
|
224
|
+
validation dialogs, task-board writes, machine-bound agent runs, and
|
|
225
|
+
user-visible results should write to the current operator account
|
|
226
|
+
`0e95801d90`. The legacy
|
|
227
|
+
`b2e06f801f` / platform-demo account still owns older public/shared records, but
|
|
228
|
+
it is being retired as the default write target. Use `nolo agent read`,
|
|
229
|
+
`nolo agent update`, and repo-native helpers as the normal entrypoints; only
|
|
230
|
+
owner-only operations that explicitly target legacy records should use the
|
|
231
|
+
maintained platform-demo token from `scripts/testUtils.ts` or a regenerated
|
|
232
|
+
token from `scripts/generateToken.ts`. Do not copy token strings into docs,
|
|
233
|
+
logs, or prompts.
|
|
219
234
|
|
|
220
235
|
Inside the current TUI, examples of supported slash commands include:
|
|
221
236
|
`/agent`, `/agents`, `/switch`, `/context` (alias `/ctx`), `/dialog`, `/doc`,
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
export const AGENT_THREAD_RECORD_PREFIX = "agent-thread";
|
|
2
|
+
export const AGENT_THREAD_INDEX_PREFIX = "agent-threadidx";
|
|
3
|
+
|
|
4
|
+
export const AGENT_THREAD_STATUSES = [
|
|
5
|
+
"pending",
|
|
6
|
+
"running",
|
|
7
|
+
"done",
|
|
8
|
+
"failed",
|
|
9
|
+
"cancelled",
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export const AGENT_THREAD_ACTIVE_STATUSES = ["pending", "running"] as const;
|
|
13
|
+
export const AGENT_THREAD_TERMINAL_STATUSES = ["done", "failed", "cancelled"] as const;
|
|
14
|
+
|
|
15
|
+
export const AGENT_THREAD_KINDS = [
|
|
16
|
+
"chat",
|
|
17
|
+
"background",
|
|
18
|
+
"inline",
|
|
19
|
+
"handoff",
|
|
20
|
+
"parallel_branch",
|
|
21
|
+
"scheduled",
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
export const AGENT_THREAD_PRESENTATION_INTENTS = [
|
|
25
|
+
"background_handoff",
|
|
26
|
+
"inline_result",
|
|
27
|
+
"handoff_speaker",
|
|
28
|
+
"parallel_branch",
|
|
29
|
+
] as const;
|
|
30
|
+
|
|
31
|
+
export type AgentThreadStatus = (typeof AGENT_THREAD_STATUSES)[number];
|
|
32
|
+
export type AgentThreadActiveStatus =
|
|
33
|
+
(typeof AGENT_THREAD_ACTIVE_STATUSES)[number];
|
|
34
|
+
export type AgentThreadTerminalStatus =
|
|
35
|
+
(typeof AGENT_THREAD_TERMINAL_STATUSES)[number];
|
|
36
|
+
export type AgentThreadKind = (typeof AGENT_THREAD_KINDS)[number];
|
|
37
|
+
export type AgentThreadPresentationIntent =
|
|
38
|
+
(typeof AGENT_THREAD_PRESENTATION_INTENTS)[number];
|
|
39
|
+
|
|
40
|
+
export type AgentThreadListSection = "running" | "future" | "recent";
|
|
41
|
+
|
|
42
|
+
export type AgentThreadSubjectRef = {
|
|
43
|
+
kind: string;
|
|
44
|
+
id: string;
|
|
45
|
+
role?: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type AgentThreadSchedule =
|
|
49
|
+
| {
|
|
50
|
+
kind: "once";
|
|
51
|
+
timezone?: string;
|
|
52
|
+
nextRunAt: number;
|
|
53
|
+
}
|
|
54
|
+
| {
|
|
55
|
+
kind: "cron";
|
|
56
|
+
timezone?: string;
|
|
57
|
+
expression: string;
|
|
58
|
+
nextRunAt: number;
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
kind: "interval";
|
|
62
|
+
timezone?: string;
|
|
63
|
+
everyMs: number;
|
|
64
|
+
nextRunAt: number;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type AgentThreadEvidence = {
|
|
68
|
+
kind: string;
|
|
69
|
+
summary?: string;
|
|
70
|
+
refs?: AgentThreadSubjectRef[];
|
|
71
|
+
data?: Record<string, unknown>;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type AgentThreadRuntimeCheckpoint = {
|
|
75
|
+
status?: string;
|
|
76
|
+
toolCallCount?: number;
|
|
77
|
+
traceSummary?: unknown;
|
|
78
|
+
lastToolNames?: string[];
|
|
79
|
+
lastAssistantText?: string;
|
|
80
|
+
evidence?: AgentThreadEvidence[];
|
|
81
|
+
policyState?: unknown;
|
|
82
|
+
runtimeBinding?: unknown;
|
|
83
|
+
errorMessage?: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type AgentThread = {
|
|
87
|
+
threadId: string;
|
|
88
|
+
title?: string;
|
|
89
|
+
summary?: string;
|
|
90
|
+
|
|
91
|
+
primaryAgentKey: string;
|
|
92
|
+
agentKeys: string[];
|
|
93
|
+
userId: string;
|
|
94
|
+
|
|
95
|
+
status: AgentThreadStatus;
|
|
96
|
+
threadKind: AgentThreadKind;
|
|
97
|
+
presentationIntent?: AgentThreadPresentationIntent;
|
|
98
|
+
|
|
99
|
+
parentThreadId?: string;
|
|
100
|
+
rootThreadId?: string;
|
|
101
|
+
|
|
102
|
+
dialogId?: string;
|
|
103
|
+
dialogKey?: string;
|
|
104
|
+
|
|
105
|
+
subjectRefs?: AgentThreadSubjectRef[];
|
|
106
|
+
|
|
107
|
+
schedule?: AgentThreadSchedule;
|
|
108
|
+
lastRunThreadId?: string;
|
|
109
|
+
|
|
110
|
+
createdAt: number;
|
|
111
|
+
updatedAt: number;
|
|
112
|
+
startedAt?: number;
|
|
113
|
+
finishedAt?: number;
|
|
114
|
+
|
|
115
|
+
runtimeCheckpoint?: AgentThreadRuntimeCheckpoint;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export function buildAgentThreadKey(args: {
|
|
119
|
+
userId: string;
|
|
120
|
+
threadId: string;
|
|
121
|
+
}): string {
|
|
122
|
+
return [AGENT_THREAD_RECORD_PREFIX, args.userId, args.threadId].join("-");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function buildAgentThreadUserRange(userId: string): {
|
|
126
|
+
gte: string;
|
|
127
|
+
lte: string;
|
|
128
|
+
} {
|
|
129
|
+
const start = `${AGENT_THREAD_RECORD_PREFIX}-${userId}-`;
|
|
130
|
+
return { gte: start, lte: `${start}\uffff` };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function buildAgentThreadByAgentStatusIndexKey(args: {
|
|
134
|
+
userId: string;
|
|
135
|
+
primaryAgentKey: string;
|
|
136
|
+
status: AgentThreadStatus;
|
|
137
|
+
threadId: string;
|
|
138
|
+
}): string {
|
|
139
|
+
return [
|
|
140
|
+
AGENT_THREAD_INDEX_PREFIX,
|
|
141
|
+
args.userId,
|
|
142
|
+
"agent",
|
|
143
|
+
args.primaryAgentKey,
|
|
144
|
+
"status",
|
|
145
|
+
args.status,
|
|
146
|
+
args.threadId,
|
|
147
|
+
].join("-");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function buildAgentThreadByAgentStatusRange(args: {
|
|
151
|
+
userId: string;
|
|
152
|
+
primaryAgentKey: string;
|
|
153
|
+
status: AgentThreadStatus;
|
|
154
|
+
}): {
|
|
155
|
+
gte: string;
|
|
156
|
+
lte: string;
|
|
157
|
+
} {
|
|
158
|
+
const start = [
|
|
159
|
+
AGENT_THREAD_INDEX_PREFIX,
|
|
160
|
+
args.userId,
|
|
161
|
+
"agent",
|
|
162
|
+
args.primaryAgentKey,
|
|
163
|
+
"status",
|
|
164
|
+
args.status,
|
|
165
|
+
"",
|
|
166
|
+
].join("-");
|
|
167
|
+
return { gte: start, lte: `${start}\uffff` };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function isAgentThreadActiveStatus(
|
|
171
|
+
status: string | null | undefined,
|
|
172
|
+
): status is AgentThreadActiveStatus {
|
|
173
|
+
return (AGENT_THREAD_ACTIVE_STATUSES as readonly string[]).includes(
|
|
174
|
+
status ?? "",
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function isAgentThreadTerminalStatus(
|
|
179
|
+
status: string | null | undefined,
|
|
180
|
+
): status is AgentThreadTerminalStatus {
|
|
181
|
+
return (AGENT_THREAD_TERMINAL_STATUSES as readonly string[]).includes(
|
|
182
|
+
status ?? "",
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function isFutureAgentThread(
|
|
187
|
+
thread: Pick<AgentThread, "schedule" | "status">,
|
|
188
|
+
nowMs: number,
|
|
189
|
+
): boolean {
|
|
190
|
+
return (
|
|
191
|
+
isAgentThreadActiveStatus(thread.status) &&
|
|
192
|
+
typeof thread.schedule?.nextRunAt === "number" &&
|
|
193
|
+
thread.schedule.nextRunAt > nowMs
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function getAgentThreadListSection(
|
|
198
|
+
thread: Pick<AgentThread, "schedule" | "status">,
|
|
199
|
+
nowMs: number,
|
|
200
|
+
): AgentThreadListSection {
|
|
201
|
+
if (isFutureAgentThread(thread, nowMs)) return "future";
|
|
202
|
+
if (isAgentThreadActiveStatus(thread.status)) return "running";
|
|
203
|
+
return "recent";
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function getAgentThreadRootId(
|
|
207
|
+
thread: Pick<AgentThread, "threadId" | "parentThreadId" | "rootThreadId">,
|
|
208
|
+
): string {
|
|
209
|
+
return thread.rootThreadId || thread.parentThreadId || thread.threadId;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function buildChildAgentThreadRelations(
|
|
213
|
+
parent: Pick<AgentThread, "threadId" | "rootThreadId">,
|
|
214
|
+
): {
|
|
215
|
+
parentThreadId: string;
|
|
216
|
+
rootThreadId: string;
|
|
217
|
+
} {
|
|
218
|
+
return {
|
|
219
|
+
parentThreadId: parent.threadId,
|
|
220
|
+
rootThreadId: parent.rootThreadId || parent.threadId,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default maxConcurrent used when an agent has no admission config.
|
|
3
|
+
* v0 policy: hard-coded to 2 until per-agent config is widely adopted.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_AGENT_THREAD_MAX_CONCURRENT = 2;
|
|
6
|
+
|
|
7
|
+
export type AgentThreadAdmissionConfig = {
|
|
8
|
+
maxConcurrent?: unknown;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type AgentThreadAdmissionAgentConfig = {
|
|
12
|
+
maxConcurrent?: unknown;
|
|
13
|
+
admission?: AgentThreadAdmissionConfig | null;
|
|
14
|
+
} | null | undefined;
|
|
15
|
+
|
|
16
|
+
export type AgentThreadAdmissionDecision =
|
|
17
|
+
| {
|
|
18
|
+
allowed: true;
|
|
19
|
+
activeThreadCount: number;
|
|
20
|
+
maxConcurrent: number;
|
|
21
|
+
}
|
|
22
|
+
| {
|
|
23
|
+
allowed: false;
|
|
24
|
+
reason: "max_concurrent_reached";
|
|
25
|
+
activeThreadCount: number;
|
|
26
|
+
maxConcurrent: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function normalizeAgentThreadMaxConcurrent(value: unknown): number | null {
|
|
30
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function resolveAgentThreadMaxConcurrent(
|
|
37
|
+
agentConfig: AgentThreadAdmissionAgentConfig,
|
|
38
|
+
): number | null {
|
|
39
|
+
const nestedLimit = normalizeAgentThreadMaxConcurrent(
|
|
40
|
+
agentConfig?.admission?.maxConcurrent,
|
|
41
|
+
);
|
|
42
|
+
if (nestedLimit != null) return nestedLimit;
|
|
43
|
+
return normalizeAgentThreadMaxConcurrent(agentConfig?.maxConcurrent);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function decideAgentThreadAdmission(input: {
|
|
47
|
+
agentConfig: AgentThreadAdmissionAgentConfig;
|
|
48
|
+
activeThreadCount: number;
|
|
49
|
+
}): AgentThreadAdmissionDecision {
|
|
50
|
+
const activeThreadCount =
|
|
51
|
+
typeof input.activeThreadCount === "number" &&
|
|
52
|
+
Number.isFinite(input.activeThreadCount) &&
|
|
53
|
+
input.activeThreadCount > 0
|
|
54
|
+
? Math.floor(input.activeThreadCount)
|
|
55
|
+
: 0;
|
|
56
|
+
const maxConcurrent =
|
|
57
|
+
resolveAgentThreadMaxConcurrent(input.agentConfig) ??
|
|
58
|
+
DEFAULT_AGENT_THREAD_MAX_CONCURRENT;
|
|
59
|
+
|
|
60
|
+
if (activeThreadCount < maxConcurrent) {
|
|
61
|
+
return {
|
|
62
|
+
allowed: true,
|
|
63
|
+
activeThreadCount,
|
|
64
|
+
maxConcurrent,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
allowed: false,
|
|
70
|
+
reason: "max_concurrent_reached",
|
|
71
|
+
activeThreadCount,
|
|
72
|
+
maxConcurrent,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -10,6 +10,11 @@ type DialogWriteOp = {
|
|
|
10
10
|
key: string;
|
|
11
11
|
value: DialogRecord;
|
|
12
12
|
};
|
|
13
|
+
type DialogSubjectRef = {
|
|
14
|
+
kind: string;
|
|
15
|
+
id: string;
|
|
16
|
+
role?: string;
|
|
17
|
+
};
|
|
13
18
|
|
|
14
19
|
function extractLastUserText(messages: AgentRuntimeChatMessage[]) {
|
|
15
20
|
const lastUser = [...messages].reverse().find((message) => message.role === "user");
|
|
@@ -38,6 +43,41 @@ function normalizeNonEmptyString(value: unknown) {
|
|
|
38
43
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
39
44
|
}
|
|
40
45
|
|
|
46
|
+
function normalizeSubjectRef(ref: unknown): DialogSubjectRef | null {
|
|
47
|
+
if (!ref || typeof ref !== "object") return null;
|
|
48
|
+
const raw = ref as Record<string, unknown>;
|
|
49
|
+
const kind = normalizeNonEmptyString(raw.kind);
|
|
50
|
+
const id = normalizeNonEmptyString(raw.id);
|
|
51
|
+
if (!kind || !id) return null;
|
|
52
|
+
const role = normalizeNonEmptyString(raw.role);
|
|
53
|
+
return {
|
|
54
|
+
kind,
|
|
55
|
+
id,
|
|
56
|
+
...(role ? { role } : {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function mergeSubjectRefs(...groups: unknown[]): DialogSubjectRef[] | undefined {
|
|
61
|
+
const refs: DialogSubjectRef[] = [];
|
|
62
|
+
const seen = new Set<string>();
|
|
63
|
+
for (const group of groups) {
|
|
64
|
+
if (!Array.isArray(group)) continue;
|
|
65
|
+
for (const item of group) {
|
|
66
|
+
const ref = normalizeSubjectRef(item);
|
|
67
|
+
if (!ref) continue;
|
|
68
|
+
const key = `${ref.kind}:${ref.id}:${ref.role ?? ""}`;
|
|
69
|
+
if (seen.has(key)) continue;
|
|
70
|
+
seen.add(key);
|
|
71
|
+
refs.push(ref);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return refs.length ? refs : undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function buildRuntimeSubjectRefs(runtimeContext?: Record<string, any> | null): DialogSubjectRef[] | undefined {
|
|
78
|
+
return mergeSubjectRefs(runtimeContext?.subjectRefs);
|
|
79
|
+
}
|
|
80
|
+
|
|
41
81
|
function buildDialogLineageFields(args: {
|
|
42
82
|
input: AgentRuntimeSaveTurnInput;
|
|
43
83
|
existingDialog?: DialogRecord | null;
|
|
@@ -105,6 +145,7 @@ export function buildAgentRuntimeDialogWritePlan(args: {
|
|
|
105
145
|
const dialogId = args.input.continueDialogId || args.createId();
|
|
106
146
|
const nowIso = new Date(args.now).toISOString();
|
|
107
147
|
const dialogKey = `dialog-${args.userId}-${dialogId}`;
|
|
148
|
+
const subjectRefs = buildRuntimeSubjectRefs(args.input.runtimeContext);
|
|
108
149
|
const dialogRecord = {
|
|
109
150
|
...(args.existingDialog && typeof args.existingDialog === "object" ? args.existingDialog : {}),
|
|
110
151
|
id: dialogId,
|
|
@@ -126,6 +167,7 @@ export function buildAgentRuntimeDialogWritePlan(args: {
|
|
|
126
167
|
usage: args.input.result.usage,
|
|
127
168
|
...(normalizeNonEmptyString(args.input.spaceId) ? { spaceId: normalizeNonEmptyString(args.input.spaceId) } : {}),
|
|
128
169
|
...(normalizeNonEmptyString(args.input.category) ? { category: normalizeNonEmptyString(args.input.category) } : {}),
|
|
170
|
+
...(subjectRefs ? { subjectRefs } : {}),
|
|
129
171
|
...buildDialogLineageFields({
|
|
130
172
|
input: args.input,
|
|
131
173
|
existingDialog: args.existingDialog,
|
package/agent-runtime/index.ts
CHANGED
|
@@ -32,6 +32,31 @@ export {
|
|
|
32
32
|
buildAgentRuntimeAgentLookupKeys,
|
|
33
33
|
shouldFetchAgentRuntimeRecordRemotely,
|
|
34
34
|
} from "./agentRecordKeys";
|
|
35
|
+
export {
|
|
36
|
+
DEFAULT_AGENT_THREAD_MAX_CONCURRENT,
|
|
37
|
+
decideAgentThreadAdmission,
|
|
38
|
+
normalizeAgentThreadMaxConcurrent,
|
|
39
|
+
resolveAgentThreadMaxConcurrent,
|
|
40
|
+
} from "./agentThreadAdmission";
|
|
41
|
+
export {
|
|
42
|
+
AGENT_THREAD_ACTIVE_STATUSES,
|
|
43
|
+
AGENT_THREAD_INDEX_PREFIX,
|
|
44
|
+
AGENT_THREAD_KINDS,
|
|
45
|
+
AGENT_THREAD_PRESENTATION_INTENTS,
|
|
46
|
+
AGENT_THREAD_RECORD_PREFIX,
|
|
47
|
+
AGENT_THREAD_STATUSES,
|
|
48
|
+
AGENT_THREAD_TERMINAL_STATUSES,
|
|
49
|
+
buildAgentThreadByAgentStatusIndexKey,
|
|
50
|
+
buildAgentThreadByAgentStatusRange,
|
|
51
|
+
buildAgentThreadKey,
|
|
52
|
+
buildAgentThreadUserRange,
|
|
53
|
+
buildChildAgentThreadRelations,
|
|
54
|
+
getAgentThreadListSection,
|
|
55
|
+
getAgentThreadRootId,
|
|
56
|
+
isAgentThreadActiveStatus,
|
|
57
|
+
isAgentThreadTerminalStatus,
|
|
58
|
+
isFutureAgentThread,
|
|
59
|
+
} from "./agentThread";
|
|
35
60
|
export { resolveAgentRuntimeConfigFromRecord } from "./agentRecordConfig";
|
|
36
61
|
export { dialogMessageRecordToAgentRuntimeMessage } from "./dialogMessageRecord";
|
|
37
62
|
export { buildAgentRuntimeDialogWritePlan } from "./dialogWritePlan";
|
|
@@ -126,6 +151,24 @@ export type {
|
|
|
126
151
|
RuntimeToolSurfaceResult,
|
|
127
152
|
RuntimeToolSurfaceVisibility,
|
|
128
153
|
} from "./runtimeToolSurface";
|
|
154
|
+
export type {
|
|
155
|
+
AgentThreadAdmissionAgentConfig,
|
|
156
|
+
AgentThreadAdmissionConfig,
|
|
157
|
+
AgentThreadAdmissionDecision,
|
|
158
|
+
} from "./agentThreadAdmission";
|
|
159
|
+
export type {
|
|
160
|
+
AgentThread,
|
|
161
|
+
AgentThreadActiveStatus,
|
|
162
|
+
AgentThreadEvidence,
|
|
163
|
+
AgentThreadKind,
|
|
164
|
+
AgentThreadListSection,
|
|
165
|
+
AgentThreadPresentationIntent,
|
|
166
|
+
AgentThreadRuntimeCheckpoint,
|
|
167
|
+
AgentThreadSchedule,
|
|
168
|
+
AgentThreadStatus,
|
|
169
|
+
AgentThreadSubjectRef,
|
|
170
|
+
AgentThreadTerminalStatus,
|
|
171
|
+
} from "./agentThread";
|
|
129
172
|
export type {
|
|
130
173
|
AgentRuntimeChatMessage,
|
|
131
174
|
AgentRuntimeDecision,
|
|
@@ -16,12 +16,14 @@ export type LocalAgentTurnInput = {
|
|
|
16
16
|
category?: string;
|
|
17
17
|
inheritedFromDialogKey?: string;
|
|
18
18
|
parentDialogId?: string;
|
|
19
|
+
runtimeContext?: Record<string, any> | null;
|
|
19
20
|
timeoutMs?: number;
|
|
20
21
|
onToolEvent?: (event: LocalAgentToolEvent) => void;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
export type LocalAgentTurnResult = AgentRuntimeResult & {
|
|
24
25
|
dialogId: string;
|
|
26
|
+
turnMessages?: AgentRuntimeChatMessage[];
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
export type LocalAgentToolEvent = {
|
|
@@ -146,6 +148,26 @@ function summarizeToolResult(content: unknown, metadata?: Record<string, unknown
|
|
|
146
148
|
return parts.join(" ");
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
function formatToolMessageContent(args: {
|
|
152
|
+
toolName: string;
|
|
153
|
+
content: string;
|
|
154
|
+
metadata?: Record<string, unknown>;
|
|
155
|
+
}) {
|
|
156
|
+
if (
|
|
157
|
+
(
|
|
158
|
+
args.toolName !== "listFiles" &&
|
|
159
|
+
args.toolName !== "globFiles" &&
|
|
160
|
+
args.toolName !== "searchFiles" &&
|
|
161
|
+
args.toolName !== "readFile"
|
|
162
|
+
) ||
|
|
163
|
+
!args.metadata ||
|
|
164
|
+
Object.keys(args.metadata).length === 0
|
|
165
|
+
) {
|
|
166
|
+
return args.content;
|
|
167
|
+
}
|
|
168
|
+
return `${args.content}\n\n[tool metadata]\n${JSON.stringify(args.metadata)}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
149
171
|
function buildMessages(args: {
|
|
150
172
|
prompt?: string;
|
|
151
173
|
history: AgentRuntimeChatMessage[];
|
|
@@ -269,7 +291,11 @@ export async function runLocalAgentTurn(
|
|
|
269
291
|
}
|
|
270
292
|
messages.push({
|
|
271
293
|
role: "tool",
|
|
272
|
-
content:
|
|
294
|
+
content: formatToolMessageContent({
|
|
295
|
+
toolName,
|
|
296
|
+
content: toolResult.content,
|
|
297
|
+
metadata: toolResult.metadata,
|
|
298
|
+
}),
|
|
273
299
|
tool_call_id: toolCall.id,
|
|
274
300
|
...(toolResult.metadata ? { tool_result_metadata: toolResult.metadata } : {}),
|
|
275
301
|
});
|
|
@@ -281,14 +307,16 @@ export async function runLocalAgentTurn(
|
|
|
281
307
|
role: "assistant",
|
|
282
308
|
content: result.content,
|
|
283
309
|
});
|
|
310
|
+
const turnMessages = messages.slice(turnStartIndex);
|
|
284
311
|
const saved = await input.adapter.saveTurn({
|
|
285
312
|
agentKey: agentConfig.key,
|
|
286
|
-
messages:
|
|
313
|
+
messages: turnMessages,
|
|
287
314
|
result: {
|
|
288
315
|
...result,
|
|
289
316
|
...(toolCallCount > 0 ? { toolCallCount } : {}),
|
|
290
317
|
...((agentConfig as any).toolSurface ? { runtimeToolSurface: (agentConfig as any).toolSurface } : {}),
|
|
291
318
|
},
|
|
319
|
+
...(input.runtimeContext ? { runtimeContext: input.runtimeContext } : {}),
|
|
292
320
|
...(input.continueDialogId ? { continueDialogId: input.continueDialogId } : {}),
|
|
293
321
|
...(input.spaceId ? { spaceId: input.spaceId } : {}),
|
|
294
322
|
...(input.category ? { category: input.category } : {}),
|
|
@@ -301,5 +329,6 @@ export async function runLocalAgentTurn(
|
|
|
301
329
|
...(toolCallCount > 0 ? { toolCallCount } : {}),
|
|
302
330
|
...((agentConfig as any).toolSurface ? { runtimeToolSurface: (agentConfig as any).toolSurface } : {}),
|
|
303
331
|
dialogId: saved.dialogId,
|
|
332
|
+
turnMessages,
|
|
304
333
|
};
|
|
305
334
|
}
|