@getpaseo/server 0.3.0-beta.3 → 0.3.0
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/dist/server/server/agent/mcp-shared.d.ts +2 -2
- package/dist/server/server/agent/providers/pi/agent.js +2 -2
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +1 -1
- package/dist/server/server/agent-history-search.d.ts +48 -0
- package/dist/server/server/agent-history-search.js +129 -0
- package/dist/server/server/session.d.ts +7 -0
- package/dist/server/server/session.js +56 -0
- package/dist/server/server/websocket-server.js +2 -0
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-280bd28c6e8031e562e84a5381d2c1c1.js → desktop-attachment-bridge-78bca55e001d8c210fd05d625c99acf2.js} +1 -1
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-280bd28c6e8031e562e84a5381d2c1c1.js.br → desktop-attachment-bridge-78bca55e001d8c210fd05d625c99acf2.js.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-78bca55e001d8c210fd05d625c99acf2.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-453c818cb8f94014304c6c7d1a2b2e40.js → desktop-attachment-store-fb478be7d05fee363960b3c2f31779a1.js} +1 -1
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-453c818cb8f94014304c6c7d1a2b2e40.js.br → desktop-attachment-store-fb478be7d05fee363960b3c2f31779a1.js.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-fb478be7d05fee363960b3c2f31779a1.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-05ab870902a891e82009b71807891c03.js → index-fa155a82030f278e4fc83bdb473c422b.js} +281 -277
- package/dist/server/web-ui/_expo/static/js/web/index-fa155a82030f278e4fc83bdb473c422b.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-fa155a82030f278e4fc83bdb473c422b.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-8edd5327b474f3356d5a859d90d9ae09.js → indexeddb-attachment-store-3800a3c9dea67ae868ad80bd1234f699.js} +1 -1
- package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-8edd5327b474f3356d5a859d90d9ae09.js.br → indexeddb-attachment-store-3800a3c9dea67ae868ad80bd1234f699.js.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-3800a3c9dea67ae868ad80bd1234f699.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-b2d51f09a55f96148455ab167edc662b.js → native-file-attachment-store-06b3e5a3594801e3ad5d3853a5aec56b.js} +3 -3
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-06b3e5a3594801e3ad5d3853a5aec56b.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-06b3e5a3594801e3ad5d3853a5aec56b.js.gz +0 -0
- package/dist/server/web-ui/index.html +1 -1
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/package.json +5 -5
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-280bd28c6e8031e562e84a5381d2c1c1.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-453c818cb8f94014304c6c7d1a2b2e40.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-05ab870902a891e82009b71807891c03.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-05ab870902a891e82009b71807891c03.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-8edd5327b474f3356d5a859d90d9ae09.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b2d51f09a55f96148455ab167edc662b.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b2d51f09a55f96148455ab167edc662b.js.gz +0 -0
|
@@ -8,9 +8,9 @@ import type { AgentProvider } from "./agent-sdk-types.js";
|
|
|
8
8
|
export declare const AgentProviderEnum: z.ZodString;
|
|
9
9
|
export declare const AgentStatusEnum: z.ZodEnum<{
|
|
10
10
|
error: "error";
|
|
11
|
+
initializing: "initializing";
|
|
11
12
|
idle: "idle";
|
|
12
13
|
running: "running";
|
|
13
|
-
initializing: "initializing";
|
|
14
14
|
closed: "closed";
|
|
15
15
|
}>;
|
|
16
16
|
export declare const ProviderModeSchema: z.ZodObject<{
|
|
@@ -83,7 +83,7 @@ export declare function serializeSnapshotWithMetadata(agentStorage: AgentStorage
|
|
|
83
83
|
createdAt: string;
|
|
84
84
|
updatedAt: string;
|
|
85
85
|
lastUserMessageAt: string | null;
|
|
86
|
-
status: "error" | "
|
|
86
|
+
status: "error" | "initializing" | "idle" | "running" | "closed";
|
|
87
87
|
capabilities: import("@getpaseo/protocol/agent-types").AgentCapabilityFlags;
|
|
88
88
|
currentModeId: string | null;
|
|
89
89
|
availableModes: import("@getpaseo/protocol/agent-types").AgentMode[];
|
|
@@ -1749,12 +1749,12 @@ export class PiRpcAgentSession {
|
|
|
1749
1749
|
this.emit(event);
|
|
1750
1750
|
}
|
|
1751
1751
|
handleMessageUpdate(event, turnId) {
|
|
1752
|
-
if (event.message.role !== "assistant") {
|
|
1752
|
+
if (event.message && event.message.role !== "assistant") {
|
|
1753
1753
|
return;
|
|
1754
1754
|
}
|
|
1755
1755
|
if (event.assistantMessageEvent.type === "text_delta") {
|
|
1756
1756
|
// Pi-compatible runtimes may emit updates without a preceding message_start.
|
|
1757
|
-
this.activeAssistantMessageId ?? (this.activeAssistantMessageId = event.message
|
|
1757
|
+
this.activeAssistantMessageId ?? (this.activeAssistantMessageId = event.message?.responseId || randomUUID());
|
|
1758
1758
|
this.emit({
|
|
1759
1759
|
type: "timeline",
|
|
1760
1760
|
provider: this.provider,
|
|
@@ -181,7 +181,7 @@ export type PiAgentSessionEvent = {
|
|
|
181
181
|
message: PiAgentMessage;
|
|
182
182
|
} | {
|
|
183
183
|
type: "message_update";
|
|
184
|
-
message
|
|
184
|
+
message?: PiAgentMessage;
|
|
185
185
|
assistantMessageEvent: PiAssistantMessageEvent;
|
|
186
186
|
} | {
|
|
187
187
|
type: "tool_execution_start";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AgentSearchMatch, AgentSnapshotPayload, ProjectPlacementPayload } from "@getpaseo/protocol/messages";
|
|
2
|
+
/**
|
|
3
|
+
* History search ranks what the daemon already knows about a session: the four
|
|
4
|
+
* names attached to it. Transcripts are deliberately out — they are unbounded,
|
|
5
|
+
* and a partial-transcript index would answer "not found" for sessions that do
|
|
6
|
+
* contain the phrase, which is worse than never claiming to search them.
|
|
7
|
+
*
|
|
8
|
+
* Field order is the tie-break order. Workspace and agent titles are what
|
|
9
|
+
* people actually recall; a project name matches every session in the repo, so
|
|
10
|
+
* it ranks last and only decides ties.
|
|
11
|
+
*/
|
|
12
|
+
export interface AgentHistorySearchCandidate {
|
|
13
|
+
agent: AgentSnapshotPayload;
|
|
14
|
+
project: ProjectPlacementPayload;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Every token has to match something, so adding a word always narrows. Tokens
|
|
18
|
+
* may land on different fields — "stripe main" finds the Stripe workspace on
|
|
19
|
+
* the main branch.
|
|
20
|
+
*/
|
|
21
|
+
export declare function scoreAgentHistoryCandidate(query: string, candidate: AgentHistorySearchCandidate): number | null;
|
|
22
|
+
/**
|
|
23
|
+
* Where the query landed in each field, for the rows that will actually be
|
|
24
|
+
* rendered. The ranker already knows this; sending it means the client never
|
|
25
|
+
* has to re-derive a second opinion that could disagree with the ranking it is
|
|
26
|
+
* explaining.
|
|
27
|
+
*/
|
|
28
|
+
export declare function describeAgentHistoryMatches(query: string, candidate: AgentHistorySearchCandidate): AgentSearchMatch[];
|
|
29
|
+
export interface RankedAgentHistoryCandidate<T extends AgentHistorySearchCandidate> {
|
|
30
|
+
candidate: T;
|
|
31
|
+
searchScore: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Ranks the whole candidate set rather than a page of it. The daemon holds
|
|
35
|
+
* every persisted agent in memory already, so search is complete by
|
|
36
|
+
* construction and the client never has to warn that it only looked at what it
|
|
37
|
+
* had loaded.
|
|
38
|
+
*
|
|
39
|
+
* A searched response is one page: the best `limit` matches, and a flag saying
|
|
40
|
+
* more matched. There is no search cursor. Offsets into a ranking that is
|
|
41
|
+
* recomputed per request duplicate and skip rows as history mutates underneath
|
|
42
|
+
* them, and a keyset cursor would buy the ability to walk past result 200 of a
|
|
43
|
+
* relevance order — which is browsing, not searching. Narrowing the query is
|
|
44
|
+
* the answer, and the global top K is exactly recoverable from each host's own
|
|
45
|
+
* top K, which is what lets several hosts merge without a federated pager.
|
|
46
|
+
*/
|
|
47
|
+
export declare function rankAgentHistoryCandidates<T extends AgentHistorySearchCandidate>(query: string, candidates: readonly T[], compareTies: (left: T, right: T) => number): RankedAgentHistoryCandidate<T>[];
|
|
48
|
+
//# sourceMappingURL=agent-history-search.d.ts.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { compareMatchScores, fuzzyPolicyForToken, matchRanges, scoreMatch, tokenizeQuery, } from "@getpaseo/protocol/search/text-match";
|
|
2
|
+
/** In tie-break order; the index into this list is a field's rank. */
|
|
3
|
+
const SEARCH_FIELDS = ["workspace", "title", "branch", "project"];
|
|
4
|
+
function searchableFields(candidate) {
|
|
5
|
+
const { agent, project } = candidate;
|
|
6
|
+
return [
|
|
7
|
+
project.workspaceName ?? "",
|
|
8
|
+
agent.title ?? "",
|
|
9
|
+
project.checkout.currentBranch ?? "",
|
|
10
|
+
project.projectName,
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
function bestFieldMatch(token, fields) {
|
|
14
|
+
const fuzzy = fuzzyPolicyForToken(token);
|
|
15
|
+
let best = null;
|
|
16
|
+
for (let fieldRank = 0; fieldRank < fields.length; fieldRank += 1) {
|
|
17
|
+
const field = fields[fieldRank];
|
|
18
|
+
if (!field)
|
|
19
|
+
continue;
|
|
20
|
+
const score = scoreMatch(token, field, { fuzzy });
|
|
21
|
+
if (!score)
|
|
22
|
+
continue;
|
|
23
|
+
if (!best || compareMatchScores(score, best.score) < 0) {
|
|
24
|
+
best = { score, fieldRank, token };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return best;
|
|
28
|
+
}
|
|
29
|
+
/** Overlapping spans from different tokens would double-mark the same glyphs. */
|
|
30
|
+
function mergeRanges(ranges) {
|
|
31
|
+
const sorted = [...ranges].sort((left, right) => left.start - right.start);
|
|
32
|
+
const merged = [];
|
|
33
|
+
for (const range of sorted) {
|
|
34
|
+
const last = merged.at(-1);
|
|
35
|
+
if (last && range.start <= last.start + last.length) {
|
|
36
|
+
last.length = Math.max(last.length, range.start + range.length - last.start);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
merged.push({ ...range });
|
|
40
|
+
}
|
|
41
|
+
return merged;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One number so the wire can carry relevance and several hosts' pages can be
|
|
45
|
+
* merged by it. Tier dominates, then which field matched, then how deep into
|
|
46
|
+
* that field the match sat.
|
|
47
|
+
*/
|
|
48
|
+
function toSearchScore(matches) {
|
|
49
|
+
let total = 0;
|
|
50
|
+
for (const match of matches) {
|
|
51
|
+
total += match.score.tier * 1000 + match.fieldRank * 100 + Math.min(match.score.offset, 99);
|
|
52
|
+
}
|
|
53
|
+
return total;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Every token has to match something, so adding a word always narrows. Tokens
|
|
57
|
+
* may land on different fields — "stripe main" finds the Stripe workspace on
|
|
58
|
+
* the main branch.
|
|
59
|
+
*/
|
|
60
|
+
export function scoreAgentHistoryCandidate(query, candidate) {
|
|
61
|
+
const matches = matchAgentHistoryCandidate(query, candidate);
|
|
62
|
+
return matches ? toSearchScore(matches) : null;
|
|
63
|
+
}
|
|
64
|
+
function matchAgentHistoryCandidate(query, candidate) {
|
|
65
|
+
const tokens = tokenizeQuery(query);
|
|
66
|
+
if (tokens.length === 0)
|
|
67
|
+
return null;
|
|
68
|
+
const fields = searchableFields(candidate);
|
|
69
|
+
const matches = [];
|
|
70
|
+
for (const token of tokens) {
|
|
71
|
+
const match = bestFieldMatch(token, fields);
|
|
72
|
+
if (!match)
|
|
73
|
+
return null;
|
|
74
|
+
matches.push(match);
|
|
75
|
+
}
|
|
76
|
+
return matches;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Where the query landed in each field, for the rows that will actually be
|
|
80
|
+
* rendered. The ranker already knows this; sending it means the client never
|
|
81
|
+
* has to re-derive a second opinion that could disagree with the ranking it is
|
|
82
|
+
* explaining.
|
|
83
|
+
*/
|
|
84
|
+
export function describeAgentHistoryMatches(query, candidate) {
|
|
85
|
+
const matches = matchAgentHistoryCandidate(query, candidate);
|
|
86
|
+
if (!matches)
|
|
87
|
+
return [];
|
|
88
|
+
const fields = searchableFields(candidate);
|
|
89
|
+
const rangesByField = new Map();
|
|
90
|
+
for (const match of matches) {
|
|
91
|
+
const field = SEARCH_FIELDS[match.fieldRank];
|
|
92
|
+
const ranges = matchRanges(match.token, fields[match.fieldRank], match.score);
|
|
93
|
+
rangesByField.set(field, [...(rangesByField.get(field) ?? []), ...ranges]);
|
|
94
|
+
}
|
|
95
|
+
return [...rangesByField.entries()].map(([field, ranges]) => ({
|
|
96
|
+
field,
|
|
97
|
+
ranges: mergeRanges(ranges),
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Ranks the whole candidate set rather than a page of it. The daemon holds
|
|
102
|
+
* every persisted agent in memory already, so search is complete by
|
|
103
|
+
* construction and the client never has to warn that it only looked at what it
|
|
104
|
+
* had loaded.
|
|
105
|
+
*
|
|
106
|
+
* A searched response is one page: the best `limit` matches, and a flag saying
|
|
107
|
+
* more matched. There is no search cursor. Offsets into a ranking that is
|
|
108
|
+
* recomputed per request duplicate and skip rows as history mutates underneath
|
|
109
|
+
* them, and a keyset cursor would buy the ability to walk past result 200 of a
|
|
110
|
+
* relevance order — which is browsing, not searching. Narrowing the query is
|
|
111
|
+
* the answer, and the global top K is exactly recoverable from each host's own
|
|
112
|
+
* top K, which is what lets several hosts merge without a federated pager.
|
|
113
|
+
*/
|
|
114
|
+
export function rankAgentHistoryCandidates(query, candidates, compareTies) {
|
|
115
|
+
const ranked = [];
|
|
116
|
+
for (const candidate of candidates) {
|
|
117
|
+
const searchScore = scoreAgentHistoryCandidate(query, candidate);
|
|
118
|
+
if (searchScore === null)
|
|
119
|
+
continue;
|
|
120
|
+
ranked.push({ candidate, searchScore });
|
|
121
|
+
}
|
|
122
|
+
ranked.sort((left, right) => {
|
|
123
|
+
if (left.searchScore !== right.searchScore)
|
|
124
|
+
return left.searchScore - right.searchScore;
|
|
125
|
+
return compareTies(left.candidate, right.candidate);
|
|
126
|
+
});
|
|
127
|
+
return ranked;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=agent-history-search.js.map
|
|
@@ -364,6 +364,13 @@ export declare class Session {
|
|
|
364
364
|
private buildActiveProjectPlacementsByWorkspaceId;
|
|
365
365
|
private collectFetchAgentsEntries;
|
|
366
366
|
private listFetchAgentsEntries;
|
|
367
|
+
/**
|
|
368
|
+
* The searched history page. Ranking has to see every candidate before it can
|
|
369
|
+
* name the best one, so this path resolves placements for the whole set
|
|
370
|
+
* instead of stopping at the page limit — that is what makes a query answer
|
|
371
|
+
* from all persisted sessions rather than from the first page of them.
|
|
372
|
+
*/
|
|
373
|
+
private listRankedAgentHistoryEntries;
|
|
367
374
|
private readonly agentsPager;
|
|
368
375
|
private decodeAgentCursor;
|
|
369
376
|
private describeWorkspaceRecord;
|
|
@@ -8,6 +8,7 @@ import { serializeAgentStreamEvent, } from "./messages.js";
|
|
|
8
8
|
import { TerminalSessionController } from "../terminal/terminal-session-controller.js";
|
|
9
9
|
import { CursorError } from "./pagination/cursor.js";
|
|
10
10
|
import { SortablePager } from "./pagination/sortable-pager.js";
|
|
11
|
+
import { describeAgentHistoryMatches, rankAgentHistoryCandidates } from "./agent-history-search.js";
|
|
11
12
|
import { buildConfigOverrides, isStoredAgentProviderAvailable, toAgentPersistenceHandle, } from "./persistence-hooks.js";
|
|
12
13
|
import { ensureAgentLoaded, ensureUnarchivedAgentLoaded } from "./agent/agent-loading.js";
|
|
13
14
|
import { formatSystemNotificationPrompt, sendPromptToAgent, waitForAgentRunStartWithTimeout, unarchiveAgentState, } from "./agent/agent-prompt.js";
|
|
@@ -131,6 +132,15 @@ export function resolveWaitForFinishError(options) {
|
|
|
131
132
|
const message = options.final?.lastError;
|
|
132
133
|
return typeof message === "string" && message.trim().length > 0 ? message : "Agent failed";
|
|
133
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Only history carries a query. The active-agents directory filters on
|
|
137
|
+
* structure and never ranks, so it always reads as no query at all.
|
|
138
|
+
*/
|
|
139
|
+
function agentDirectorySearchQuery(request) {
|
|
140
|
+
if (request.type !== "fetch_agent_history_request")
|
|
141
|
+
return "";
|
|
142
|
+
return request.search?.trim() ?? "";
|
|
143
|
+
}
|
|
134
144
|
class SessionRequestError extends Error {
|
|
135
145
|
constructor(code, message) {
|
|
136
146
|
super(message);
|
|
@@ -3198,6 +3208,17 @@ export class Session {
|
|
|
3198
3208
|
placementByWorkspaceId.set(workspaceId, placementPromise);
|
|
3199
3209
|
return placementPromise;
|
|
3200
3210
|
};
|
|
3211
|
+
const search = agentDirectorySearchQuery(request);
|
|
3212
|
+
if (search) {
|
|
3213
|
+
return this.listRankedAgentHistoryEntries({
|
|
3214
|
+
search,
|
|
3215
|
+
agents,
|
|
3216
|
+
sort,
|
|
3217
|
+
filter,
|
|
3218
|
+
getPlacement,
|
|
3219
|
+
page: request.page,
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3201
3222
|
let candidates = [...agents];
|
|
3202
3223
|
candidates.sort((left, right) => this.agentsPager.compare(left, right, sort));
|
|
3203
3224
|
const cursorToken = request.page?.cursor;
|
|
@@ -3226,6 +3247,41 @@ export class Session {
|
|
|
3226
3247
|
},
|
|
3227
3248
|
};
|
|
3228
3249
|
}
|
|
3250
|
+
/**
|
|
3251
|
+
* The searched history page. Ranking has to see every candidate before it can
|
|
3252
|
+
* name the best one, so this path resolves placements for the whole set
|
|
3253
|
+
* instead of stopping at the page limit — that is what makes a query answer
|
|
3254
|
+
* from all persisted sessions rather than from the first page of them.
|
|
3255
|
+
*/
|
|
3256
|
+
async listRankedAgentHistoryEntries(params) {
|
|
3257
|
+
const { search, agents, sort, filter, getPlacement, page } = params;
|
|
3258
|
+
if (page?.cursor) {
|
|
3259
|
+
// A ranked result set has no pages to walk, so a cursor here is caller
|
|
3260
|
+
// misuse. Returning the ranked head instead would hide it.
|
|
3261
|
+
throw new SessionRequestError("invalid_cursor", "A history search returns one ranked page; it cannot be paged with a cursor.");
|
|
3262
|
+
}
|
|
3263
|
+
const allEntries = await this.collectFetchAgentsEntries({
|
|
3264
|
+
candidates: agents,
|
|
3265
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
3266
|
+
getPlacement,
|
|
3267
|
+
filter,
|
|
3268
|
+
});
|
|
3269
|
+
const ranked = rankAgentHistoryCandidates(search, allEntries, (left, right) => this.agentsPager.compare(left.agent, right.agent, sort));
|
|
3270
|
+
const limit = page?.limit ?? 200;
|
|
3271
|
+
// Ranges are derived only for the rows that will be rendered; ranking
|
|
3272
|
+
// itself never needs them.
|
|
3273
|
+
const entries = ranked.slice(0, limit).map((result) => Object.assign({}, result.candidate, {
|
|
3274
|
+
searchScore: result.searchScore,
|
|
3275
|
+
searchMatches: describeAgentHistoryMatches(search, result.candidate),
|
|
3276
|
+
}));
|
|
3277
|
+
return {
|
|
3278
|
+
entries,
|
|
3279
|
+
// No next page exists, so `hasMore` is false and truncation is reported
|
|
3280
|
+
// on its own field. See the note on rankAgentHistoryCandidates.
|
|
3281
|
+
pageInfo: { nextCursor: null, prevCursor: null, hasMore: false },
|
|
3282
|
+
searchTruncated: ranked.length > limit,
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3229
3285
|
decodeAgentCursor(token, sort) {
|
|
3230
3286
|
try {
|
|
3231
3287
|
return this.agentsPager.decode(token, sort);
|
|
@@ -1062,6 +1062,8 @@ export class VoiceAssistantWebSocketServer {
|
|
|
1062
1062
|
rewind: true,
|
|
1063
1063
|
// COMPAT(agentTimelinePromptIndex): added in v0.2.X, drop the gate when floor >= v0.2.X.
|
|
1064
1064
|
agentTimelinePromptIndex: true,
|
|
1065
|
+
// COMPAT(agentHistorySearch): added in v0.3.0, remove gate after 2027-02-07.
|
|
1066
|
+
agentHistorySearch: true,
|
|
1065
1067
|
// COMPAT(checkoutRefresh): added in v0.1.86, remove gate after 2026-11-29.
|
|
1066
1068
|
checkoutRefresh: true,
|
|
1067
1069
|
// COMPAT(workspaceMultiplicity): added in v0.1.97, drop the gate when floor >= v0.1.97
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4676,[4123,4124]);
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4675,[4117]);
|
|
Binary file
|