@opengeni/api-router 2.10.0-canary.0 → 2.10.0-canary.2
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/app.js +1 -1
- package/dist/{chunk-XXH7DW34.js → chunk-BVX5ASFY.js} +1559 -798
- package/dist/chunk-BVX5ASFY.js.map +1 -0
- package/dist/codemode.d.ts +3 -0
- package/dist/index.js +1 -1
- package/dist/integrations/slack-interactions.d.ts +1 -1
- package/dist/mcp/command-read.d.ts +24 -0
- package/dist/mcp/scheduled-task-view.d.ts +3 -3
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/session-event-view.d.ts +86 -0
- package/dist/sandbox/channel-a.d.ts +2 -0
- package/dist/sandbox/rematerialize.d.ts +2 -0
- package/dist/sandbox/viewer.d.ts +2 -0
- package/dist/session-event-view-MU3HMNV3.js +264 -0
- package/dist/session-event-view-MU3HMNV3.js.map +1 -0
- package/dist/site-uploads.d.ts +41 -0
- package/dist/workspace-artifact-content.d.ts +4 -4
- package/package.json +19 -19
- package/src/app.ts +20 -0
- package/src/codemode.ts +52 -0
- package/src/integrations/oauth-client.ts +51 -7
- package/src/mcp/command-read.ts +109 -0
- package/src/mcp/server.ts +287 -153
- package/src/mcp/session-event-view.ts +336 -0
- package/src/mcp/session-wait.ts +1 -1
- package/src/routes/github.ts +124 -1
- package/src/routes/scheduled-tasks.ts +19 -1
- package/src/routes/sessions.ts +150 -7
- package/src/routes/workspace-artifacts.ts +92 -21
- package/src/sandbox/channel-a.ts +5 -0
- package/src/sandbox/rematerialize.ts +46 -3
- package/src/sandbox/viewer.ts +3 -0
- package/src/site-uploads.ts +202 -0
- package/src/workspace-artifact-content.ts +20 -39
- package/dist/chunk-XXH7DW34.js.map +0 -1
package/dist/codemode.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type AccessGrant, type AttemptToolCatalog, type CodemodeCallSubmission as CodemodeCallSubmissionValue, type CodemodeOperation } from "@opengeni/contracts";
|
|
2
2
|
import type { ApiRouteDeps } from "@opengeni/core";
|
|
3
|
+
/** Reuse normal REST handlers, including their resource/command authorization.
|
|
4
|
+
* The exact attempt is checked before issuing this internal-only credential. */
|
|
5
|
+
export declare function codemodeSessionRequest(deps: ApiRouteDeps, grant: AccessGrant, request: Request, path: string): Promise<Request>;
|
|
3
6
|
export type CodemodeGrantAuthority = {
|
|
4
7
|
accountId: string;
|
|
5
8
|
workspaceId: string;
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ export declare const SLACK_SESSION_INSTRUCTIONS: string;
|
|
|
19
19
|
* selection at session creation while keeping Slack mutations out of the model
|
|
20
20
|
* surface; interaction delivery remains owned by the durable delivery pump.
|
|
21
21
|
*/
|
|
22
|
-
export declare const SLACK_TASK_FIRST_PARTY_MCP_TOOLS: ("artifacts_archive" | "artifacts_create" | "artifacts_get_source" | "artifacts_list" | "artifacts_publish" | "artifacts_restore" | "artifacts_rollback" | "atlassian_get" | "atlassian_search" | "atlassian_sources_list" | "browser_act" | "browser_auth" | "browser_clipboard" | "browser_debug" | "browser_identity" | "browser_lifecycle" | "browser_observe" | "browser_open" | "browser_publish" | "browser_tabs" | "capability_authorization_request" | "capability_catalog_search" | "command_wait" | "company_profile_confirm" | "company_profile_propose" | "computer_act" | "computer_clipboard" | "computer_lifecycle" | "computer_observe" | "computer_open" | "computer_targets" | "connected_machine_remove" | "editable_artifact_apply" | "editable_artifact_create" | "editable_artifact_export" | "editable_artifact_export_status" | "editable_artifact_get" | "editable_artifact_import" | "editable_artifact_inspect" | "editable_artifact_list" | "environment_list" | "environment_set_variable" | "fiken_bank_accounts_list" | "fiken_companies_list" | "fiken_contact_create" | "fiken_contacts_list" | "fiken_invoice_draft_create" | "fiken_invoice_get" | "fiken_invoices_list" | "fiken_products_list" | "fiken_purchases_list" | "fiken_sales_list" | "github_connect_link" | "github_repositories_list" | "goal_complete" | "goal_pause" | "goal_progress" | "goal_set" | "goal_update" | "instruction_policy_propose" | "interaction_discover" | "interaction_request_human" | "knowledge_correct" | "knowledge_propose" | "memory_correct" | "memory_save" | "memory_search" | "preference_propose" | "preference_registry_get" | "preference_registry_summary" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "remember" | "remember_confirm" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_file_publish" | "sandbox_provision" | "sandbox_swap" | "sandboxes_list" | "scheduled_task_runs_list" | "scheduled_tasks_create" | "scheduled_tasks_delete" | "scheduled_tasks_get" | "scheduled_tasks_list" | "scheduled_tasks_pause" | "scheduled_tasks_resume" | "scheduled_tasks_trigger" | "scheduled_tasks_update" | "session_create" | "session_events" | "session_get" | "session_human_input_respond" | "session_pause" | "session_resume" | "session_send_message" | "session_steer" | "session_wait" | "sessions_list" | "set_other_session_title" | "set_session_title" | "slack_bot_channel_history" | "slack_bot_delete_message" | "slack_bot_file_content" | "slack_bot_file_info" | "slack_bot_list_channels" | "slack_bot_list_files" | "slack_bot_list_users" | "slack_bot_post_message" | "slack_bot_search" | "slack_bot_thread_replies" | "social_connections_list" | "social_daily_analysis_context" | "social_mentions_live" | "social_post_reply" | "social_posts_recent" | "social_posts_sync" | "social_search_live" | "social_thread_fetch" | "task_note_archive" | "task_note_promote_instruction_policy" | "task_note_promote_knowledge" | "task_note_promote_preference" | "task_note_replace" | "task_note_save" | "task_notes_list" | "variable_set_get_variable" | "variable_set_list" | "variable_set_set_variable" | "wait_for_input" | "work_claim_release" | "work_claim_upsert" | "x_accounts_list" | "x_mentions_live" | "x_post_reply" | "x_posts_sync" | "x_search_live" | "x_thread_fetch")[];
|
|
22
|
+
export declare const SLACK_TASK_FIRST_PARTY_MCP_TOOLS: ("artifacts_archive" | "artifacts_create" | "artifacts_get_source" | "artifacts_list" | "artifacts_prepare_upload" | "artifacts_publish" | "artifacts_restore" | "artifacts_rollback" | "atlassian_get" | "atlassian_search" | "atlassian_sources_list" | "browser_act" | "browser_auth" | "browser_clipboard" | "browser_debug" | "browser_identity" | "browser_lifecycle" | "browser_observe" | "browser_open" | "browser_publish" | "browser_tabs" | "capability_authorization_request" | "capability_catalog_search" | "command_read" | "command_wait" | "company_profile_confirm" | "company_profile_propose" | "computer_act" | "computer_clipboard" | "computer_lifecycle" | "computer_observe" | "computer_open" | "computer_targets" | "connected_machine_remove" | "editable_artifact_apply" | "editable_artifact_create" | "editable_artifact_export" | "editable_artifact_export_status" | "editable_artifact_get" | "editable_artifact_import" | "editable_artifact_inspect" | "editable_artifact_list" | "environment_list" | "environment_set_variable" | "fiken_bank_accounts_list" | "fiken_companies_list" | "fiken_contact_create" | "fiken_contacts_list" | "fiken_invoice_draft_create" | "fiken_invoice_get" | "fiken_invoices_list" | "fiken_products_list" | "fiken_purchases_list" | "fiken_sales_list" | "github_connect_link" | "github_repositories_list" | "goal_complete" | "goal_pause" | "goal_progress" | "goal_resume" | "goal_set" | "goal_update" | "instruction_policy_propose" | "interaction_discover" | "interaction_request_human" | "knowledge_correct" | "knowledge_propose" | "memory_correct" | "memory_save" | "memory_search" | "preference_propose" | "preference_registry_get" | "preference_registry_summary" | "reddit_accounts_list" | "reddit_mentions_live" | "reddit_post_reply" | "reddit_posts_sync" | "reddit_search_live" | "reddit_thread_fetch" | "remember" | "remember_confirm" | "rig_get" | "rig_list" | "rig_promote" | "rig_propose_change" | "rig_verify" | "run_on" | "sandbox_attach" | "sandbox_file_publish" | "sandbox_provision" | "sandbox_swap" | "sandboxes_list" | "scheduled_task_runs_list" | "scheduled_tasks_create" | "scheduled_tasks_delete" | "scheduled_tasks_get" | "scheduled_tasks_list" | "scheduled_tasks_pause" | "scheduled_tasks_resume" | "scheduled_tasks_trigger" | "scheduled_tasks_update" | "session_create" | "session_events" | "session_get" | "session_human_input_respond" | "session_pause" | "session_resume" | "session_send_message" | "session_steer" | "session_wait" | "sessions_list" | "set_other_session_title" | "set_session_title" | "slack_bot_channel_history" | "slack_bot_delete_message" | "slack_bot_file_content" | "slack_bot_file_info" | "slack_bot_list_channels" | "slack_bot_list_files" | "slack_bot_list_users" | "slack_bot_post_message" | "slack_bot_search" | "slack_bot_thread_replies" | "social_connections_list" | "social_daily_analysis_context" | "social_mentions_live" | "social_post_reply" | "social_posts_recent" | "social_posts_sync" | "social_search_live" | "social_thread_fetch" | "task_note_archive" | "task_note_promote_instruction_policy" | "task_note_promote_knowledge" | "task_note_promote_preference" | "task_note_replace" | "task_note_save" | "task_notes_list" | "variable_set_get_variable" | "variable_set_list" | "variable_set_set_variable" | "wait_for_input" | "work_claim_release" | "work_claim_upsert" | "x_accounts_list" | "x_mentions_live" | "x_post_reply" | "x_posts_sync" | "x_search_live" | "x_thread_fetch")[];
|
|
23
23
|
export type NormalizedSlackInteraction = {
|
|
24
24
|
providerEventId: string;
|
|
25
25
|
providerMessageId: string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SessionEvent } from "@opengeni/contracts";
|
|
2
|
+
export declare const COMMAND_READ_MAX_WAIT_SECONDS = 50;
|
|
3
|
+
export declare const COMMAND_WAIT_DEFAULT_SECONDS = 45;
|
|
4
|
+
/** Shared provider-neutral command_read/command_wait operation. Notifications
|
|
5
|
+
* are only wake hints. Every result, including timeout, comes from durable DB
|
|
6
|
+
* state. Subscribe before reading to close the finish/subscription race, and
|
|
7
|
+
* periodically recheck durable state because live hints may be lost. */
|
|
8
|
+
export declare function readCommandWithWait<T extends {
|
|
9
|
+
terminal: boolean;
|
|
10
|
+
chunks: unknown[];
|
|
11
|
+
hasMore?: boolean;
|
|
12
|
+
}>(input: {
|
|
13
|
+
commandId: string;
|
|
14
|
+
waitSeconds?: number;
|
|
15
|
+
maxOutputBytes?: number | undefined;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
read: () => Promise<T>;
|
|
18
|
+
subscribe: (onEvents: (events: SessionEvent[]) => void) => Promise<() => void>;
|
|
19
|
+
}): Promise<T & {
|
|
20
|
+
waitedMs: number;
|
|
21
|
+
timedOut: boolean;
|
|
22
|
+
aborted: boolean;
|
|
23
|
+
liveFanout: boolean;
|
|
24
|
+
}>;
|
|
@@ -82,8 +82,8 @@ export declare function scheduledTaskMcpSummary(task: ScheduledTask): {
|
|
|
82
82
|
runMode: "existing_session" | "new_session_per_run" | "reusable_session";
|
|
83
83
|
overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
|
|
84
84
|
action: {
|
|
85
|
+
readonly sourceId?: never;
|
|
85
86
|
kind: "agent_turn";
|
|
86
|
-
sourceId?: never;
|
|
87
87
|
sourceGeneration?: never;
|
|
88
88
|
sourceLifecycleGeneration?: never;
|
|
89
89
|
destination?: never;
|
|
@@ -205,8 +205,8 @@ export declare function boundScheduledTaskDetailMcp(task: ScheduledTask): {
|
|
|
205
205
|
runMode: "existing_session" | "new_session_per_run" | "reusable_session";
|
|
206
206
|
overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
|
|
207
207
|
action: {
|
|
208
|
+
readonly sourceId?: never;
|
|
208
209
|
kind: "agent_turn";
|
|
209
|
-
sourceId?: never;
|
|
210
210
|
sourceGeneration?: never;
|
|
211
211
|
sourceLifecycleGeneration?: never;
|
|
212
212
|
destination?: never;
|
|
@@ -389,8 +389,8 @@ export declare function boundScheduledTaskMcpPage(input: {
|
|
|
389
389
|
runMode: "existing_session" | "new_session_per_run" | "reusable_session";
|
|
390
390
|
overlapPolicy: "allow_concurrent" | "buffer_one" | "skip";
|
|
391
391
|
action: {
|
|
392
|
+
readonly sourceId?: never;
|
|
392
393
|
kind: "agent_turn";
|
|
393
|
-
sourceId?: never;
|
|
394
394
|
sourceGeneration?: never;
|
|
395
395
|
sourceLifecycleGeneration?: never;
|
|
396
396
|
destination?: never;
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -195,6 +195,7 @@ export declare function capSessionDiscoveryCompactPage(page: Awaited<ReturnType<
|
|
|
195
195
|
previewOmissionReason: "aggregatePreviewBudget";
|
|
196
196
|
previewDrillDownTool: "session_events";
|
|
197
197
|
previewDrillDownInput: {
|
|
198
|
+
view: "debug";
|
|
198
199
|
direction: "before";
|
|
199
200
|
limit: 1;
|
|
200
201
|
mode: "monitoring";
|
|
@@ -309,6 +310,7 @@ export declare function capSessionDiscoveryPage(page: Awaited<ReturnType<typeof
|
|
|
309
310
|
omissionReason: "aggregatePreviewBudget" | null;
|
|
310
311
|
drillDownTool: "session_events";
|
|
311
312
|
drillDownInput: {
|
|
313
|
+
view: "debug";
|
|
312
314
|
direction: "before";
|
|
313
315
|
limit: 1;
|
|
314
316
|
mode: "monitoring";
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { SessionEventSliceOptions, SessionEventSlicePage } from "@opengeni/db/session-event-slices";
|
|
3
|
+
export declare const SESSION_EVENT_VIEW_MAX_BYTES: number;
|
|
4
|
+
declare const selectionSchema: z.ZodObject<{
|
|
5
|
+
sessionId: z.ZodString;
|
|
6
|
+
view: z.ZodEnum<{
|
|
7
|
+
conversation: "conversation";
|
|
8
|
+
results: "results";
|
|
9
|
+
tools: "tools";
|
|
10
|
+
}>;
|
|
11
|
+
includeArguments: z.ZodBoolean;
|
|
12
|
+
includeOutput: z.ZodBoolean;
|
|
13
|
+
callId: z.ZodNullable<z.ZodString>;
|
|
14
|
+
direction: z.ZodEnum<{
|
|
15
|
+
after: "after";
|
|
16
|
+
before: "before";
|
|
17
|
+
}>;
|
|
18
|
+
after: z.ZodNumber;
|
|
19
|
+
before: z.ZodNullable<z.ZodNumber>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
type Selection = z.infer<typeof selectionSchema>;
|
|
22
|
+
export type SessionEventViewInput = {
|
|
23
|
+
sessionId: string;
|
|
24
|
+
view?: Selection["view"] | undefined;
|
|
25
|
+
after?: number | undefined;
|
|
26
|
+
before?: number | undefined;
|
|
27
|
+
direction?: Selection["direction"] | undefined;
|
|
28
|
+
limit?: number | undefined;
|
|
29
|
+
cursor?: string | undefined;
|
|
30
|
+
callId?: string | undefined;
|
|
31
|
+
includeArguments?: boolean | undefined;
|
|
32
|
+
includeOutput?: boolean | undefined;
|
|
33
|
+
};
|
|
34
|
+
type Item = {
|
|
35
|
+
sequence: number;
|
|
36
|
+
turnId?: string;
|
|
37
|
+
role?: string;
|
|
38
|
+
text?: string;
|
|
39
|
+
} & Record<string, unknown>;
|
|
40
|
+
type ReadPage = (options: SessionEventSliceOptions) => Promise<SessionEventSlicePage>;
|
|
41
|
+
/** A cursor is a bounded selector, never authority. The caller reauthorizes every read. */
|
|
42
|
+
export declare function resolveSessionEventView(input: SessionEventViewInput): {
|
|
43
|
+
selection: {
|
|
44
|
+
sessionId: string;
|
|
45
|
+
view: "conversation" | "results" | "tools";
|
|
46
|
+
includeArguments: boolean;
|
|
47
|
+
includeOutput: boolean;
|
|
48
|
+
callId: string | null;
|
|
49
|
+
direction: "after" | "before";
|
|
50
|
+
after: number;
|
|
51
|
+
before: number | null;
|
|
52
|
+
};
|
|
53
|
+
continuation: {
|
|
54
|
+
v: 1 | 2;
|
|
55
|
+
selection: {
|
|
56
|
+
sessionId: string;
|
|
57
|
+
view: "conversation" | "results" | "tools";
|
|
58
|
+
includeArguments: boolean;
|
|
59
|
+
includeOutput: boolean;
|
|
60
|
+
callId: string | null;
|
|
61
|
+
direction: "after" | "before";
|
|
62
|
+
after: number;
|
|
63
|
+
before: number | null;
|
|
64
|
+
};
|
|
65
|
+
sequence: number | null;
|
|
66
|
+
offset: number;
|
|
67
|
+
} | null;
|
|
68
|
+
};
|
|
69
|
+
/** Read-only projection over the existing RLS/audit query. No command observations. */
|
|
70
|
+
export declare function readSessionEventView(input: SessionEventViewInput, read: ReadPage): Promise<{
|
|
71
|
+
view: "conversation" | "results" | "tools";
|
|
72
|
+
direction: "after" | "before";
|
|
73
|
+
events: Item[];
|
|
74
|
+
nextAfter: number | null;
|
|
75
|
+
nextBefore: number | null;
|
|
76
|
+
hasMore: boolean;
|
|
77
|
+
nextCursor: string | null;
|
|
78
|
+
sourceExact: boolean;
|
|
79
|
+
sourceLoss?: {
|
|
80
|
+
reason: "structured_value_exceeds_budget";
|
|
81
|
+
completeTextAvailable: false;
|
|
82
|
+
message: string;
|
|
83
|
+
};
|
|
84
|
+
maxBytes: number;
|
|
85
|
+
}>;
|
|
86
|
+
export {};
|
|
@@ -3,11 +3,13 @@ import type { Session } from "@opengeni/contracts";
|
|
|
3
3
|
import { type Database, type LeaseSnapshot } from "@opengeni/db";
|
|
4
4
|
import { type EventBus } from "@opengeni/events";
|
|
5
5
|
import { type Observability } from "@opengeni/observability";
|
|
6
|
+
import type { ObjectStorage } from "@opengeni/storage";
|
|
6
7
|
import { SandboxChannelAService, type ChannelASession, type EstablishedSandboxSession, type RoutingSandboxSession } from "@opengeni/runtime/sandbox";
|
|
7
8
|
export type ChannelAServices = {
|
|
8
9
|
db: Database;
|
|
9
10
|
settings: Settings;
|
|
10
11
|
bus: EventBus;
|
|
12
|
+
objectStorage?: ObjectStorage | null;
|
|
11
13
|
observability?: Observability | undefined;
|
|
12
14
|
};
|
|
13
15
|
export type ChannelAOperation = "fs.list" | "fs.list-batch" | "fs.read" | "artifact.publish" | "fs.write" | "fs.delete" | "fs.move" | "fs.mkdir" | "git.status" | "git.diff" | "git.read-batch" | "git.log" | "git.show" | "terminal.exec" | "terminal.pty.open" | "terminal.pty.write" | "terminal.pty.resize" | "terminal.pty.close" | "browser.create" | "browser.resume" | "browser.suspend" | "browser.end" | "browser.read" | "browser.action" | "browser.control" | "browser.download.save" | "browser.attach" | "computer.create" | "computer.end" | "computer.read" | "computer.action" | "computer.control" | "computer.attach";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Settings } from "@opengeni/config";
|
|
2
2
|
import { type Database, type LeaseSnapshot } from "@opengeni/db";
|
|
3
3
|
import { type EstablishedSandboxSession } from "@opengeni/runtime/sandbox";
|
|
4
|
+
import type { ObjectStorage } from "@opengeni/storage";
|
|
4
5
|
/** The sole API-direct cold->warming owner path used by Channel A and viewer
|
|
5
6
|
* attach. It never publishes warm until archive identity, hydrated tree, command
|
|
6
7
|
* routing, provider identity, and the selected rematerialization attempt all
|
|
@@ -18,6 +19,7 @@ export declare function establishApiSandboxSpawner(input: {
|
|
|
18
19
|
acquiredLease: LeaseSnapshot;
|
|
19
20
|
fallbackEnvelope: Record<string, unknown> | null;
|
|
20
21
|
dataPlaneUrl: string | null;
|
|
22
|
+
objectStorage?: ObjectStorage | null;
|
|
21
23
|
}): Promise<{
|
|
22
24
|
established: EstablishedSandboxSession;
|
|
23
25
|
lease: LeaseSnapshot;
|
package/dist/sandbox/viewer.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Settings } from "@opengeni/config";
|
|
|
2
2
|
import { type Session } from "@opengeni/contracts";
|
|
3
3
|
import { type Database, type LeaseSnapshot, type SandboxRecord } from "@opengeni/db";
|
|
4
4
|
import { type EventBus } from "@opengeni/events";
|
|
5
|
+
import type { ObjectStorage } from "@opengeni/storage";
|
|
5
6
|
import { establishSandboxSessionFromEnvelope, type EstablishedSandboxSession } from "@opengeni/runtime/sandbox";
|
|
6
7
|
/** The minimal services a viewer op needs: the DB + settings (lease cadence +
|
|
7
8
|
* the sandbox client construction the leaf reads from settings). The bus is
|
|
@@ -11,6 +12,7 @@ export type ViewerServices = {
|
|
|
11
12
|
db: Database;
|
|
12
13
|
settings: Settings;
|
|
13
14
|
bus?: EventBus;
|
|
15
|
+
objectStorage?: ObjectStorage | null;
|
|
14
16
|
/** Provider-establish dependency used by API-direct readiness and stream
|
|
15
17
|
* operations. Production uses the runtime leaf; isolated tests may supply a
|
|
16
18
|
* deterministic provider without replacing a process-global module. */
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// src/mcp/session-event-view.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var SESSION_EVENT_VIEW_MAX_BYTES = 16 * 1024;
|
|
4
|
+
var selectionSchema = z.object({
|
|
5
|
+
sessionId: z.string().uuid(),
|
|
6
|
+
view: z.enum(["conversation", "results", "tools"]),
|
|
7
|
+
includeArguments: z.boolean(),
|
|
8
|
+
includeOutput: z.boolean(),
|
|
9
|
+
callId: z.string().max(512).refine(
|
|
10
|
+
(value) => Buffer.byteLength(JSON.stringify(value), "utf8") <= 2048,
|
|
11
|
+
"callId exceeds the encoded cursor budget"
|
|
12
|
+
).nullable(),
|
|
13
|
+
direction: z.enum(["before", "after"]),
|
|
14
|
+
after: z.number().int().nonnegative(),
|
|
15
|
+
before: z.number().int().positive().nullable()
|
|
16
|
+
});
|
|
17
|
+
var cursorSchema = z.object({
|
|
18
|
+
v: z.union([z.literal(1), z.literal(2)]),
|
|
19
|
+
selection: selectionSchema,
|
|
20
|
+
sequence: z.number().int().positive().nullable(),
|
|
21
|
+
offset: z.number().int().nonnegative().max(2147483647)
|
|
22
|
+
});
|
|
23
|
+
var types = {
|
|
24
|
+
conversation: ["user.message", "agent.message.completed"],
|
|
25
|
+
// Final turn output is authoritative: do not repeat message.completed text.
|
|
26
|
+
results: ["turn.completed", "turn.failed", "goal.completed", "goal.paused", "tool.auth_needed"],
|
|
27
|
+
tools: ["agent.toolCall.created", "agent.toolCall.output"]
|
|
28
|
+
};
|
|
29
|
+
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
30
|
+
var bytes = (value) => Buffer.byteLength(JSON.stringify(value, null, 2), "utf8");
|
|
31
|
+
var encode = (selection, sequence = null, offset = 0, v = 2) => Buffer.from(JSON.stringify({ v, selection, sequence, offset })).toString("base64url");
|
|
32
|
+
function resolveSessionEventView(input) {
|
|
33
|
+
let continuation = null;
|
|
34
|
+
if (input.cursor !== void 0) {
|
|
35
|
+
if (input.cursor.length > 4096)
|
|
36
|
+
throw new Error("session_events cursor exceeds 4096 characters");
|
|
37
|
+
try {
|
|
38
|
+
continuation = cursorSchema.parse(
|
|
39
|
+
JSON.parse(Buffer.from(input.cursor, "base64url").toString())
|
|
40
|
+
);
|
|
41
|
+
} catch {
|
|
42
|
+
throw new Error("Invalid session_events cursor");
|
|
43
|
+
}
|
|
44
|
+
const previous = continuation.selection;
|
|
45
|
+
for (const key of [
|
|
46
|
+
"sessionId",
|
|
47
|
+
"view",
|
|
48
|
+
"includeArguments",
|
|
49
|
+
"includeOutput",
|
|
50
|
+
"callId",
|
|
51
|
+
"direction",
|
|
52
|
+
"after",
|
|
53
|
+
"before"
|
|
54
|
+
]) {
|
|
55
|
+
if (input[key] !== void 0 && input[key] !== previous[key]) {
|
|
56
|
+
throw new Error(`session_events cursor cannot change ${key}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const selection = continuation?.selection ?? selectionSchema.parse({
|
|
61
|
+
sessionId: input.sessionId,
|
|
62
|
+
view: input.view ?? "conversation",
|
|
63
|
+
includeArguments: input.includeArguments ?? false,
|
|
64
|
+
includeOutput: input.includeOutput ?? false,
|
|
65
|
+
callId: input.callId ?? null,
|
|
66
|
+
direction: input.direction ?? (input.before !== void 0 || input.after === void 0 ? "before" : "after"),
|
|
67
|
+
after: input.after ?? 0,
|
|
68
|
+
before: input.before ?? null
|
|
69
|
+
});
|
|
70
|
+
if (selection.view !== "tools" && (selection.callId || selection.includeArguments || selection.includeOutput)) {
|
|
71
|
+
throw new Error("callId/includeArguments/includeOutput require view=tools");
|
|
72
|
+
}
|
|
73
|
+
if (continuation && (continuation.sequence === null && continuation.offset !== 0 || continuation.sequence !== null && (continuation.sequence <= selection.after || selection.before !== null && continuation.sequence >= selection.before)))
|
|
74
|
+
throw new Error("Invalid session_events cursor position");
|
|
75
|
+
return { selection, continuation };
|
|
76
|
+
}
|
|
77
|
+
function project(event, selection) {
|
|
78
|
+
if (event.duplicateOfEventId || event.turnAssociation && event.turnAssociation !== "current")
|
|
79
|
+
return null;
|
|
80
|
+
const p = record(event.payload);
|
|
81
|
+
const base = { sequence: event.sequence, ...event.turnId ? { turnId: event.turnId } : {} };
|
|
82
|
+
if (selection.view === "conversation") {
|
|
83
|
+
return typeof p.text === "string" && p.text.length > 0 ? { ...base, role: event.type === "user.message" ? "user" : "assistant", text: p.text } : null;
|
|
84
|
+
}
|
|
85
|
+
if (selection.view === "results") {
|
|
86
|
+
if (event.type === "turn.completed" && ("maintenance" in p || "segmentLimit" in p)) return null;
|
|
87
|
+
const value2 = event.type === "turn.completed" ? p.output ?? p.result : p;
|
|
88
|
+
if (value2 === void 0 || value2 === "") return null;
|
|
89
|
+
return {
|
|
90
|
+
...base,
|
|
91
|
+
type: event.type,
|
|
92
|
+
text: typeof value2 === "string" ? value2 : JSON.stringify(value2)
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const callId = p.callId ?? p.call_id ?? p.id;
|
|
96
|
+
if (selection.callId !== null && selection.callId !== callId) return null;
|
|
97
|
+
const output = event.type === "agent.toolCall.output";
|
|
98
|
+
const value = output ? p.output : p.arguments ?? p.args;
|
|
99
|
+
return {
|
|
100
|
+
...base,
|
|
101
|
+
callId,
|
|
102
|
+
kind: output ? "result" : "call",
|
|
103
|
+
...typeof p.name === "string" ? { name: p.name } : {},
|
|
104
|
+
...p.identityOmitted === true ? { identityOmitted: true } : {},
|
|
105
|
+
...p.isError === true || record(value).isError === true ? { isError: true } : {},
|
|
106
|
+
...(output ? selection.includeOutput : selection.includeArguments) && value !== void 0 ? {
|
|
107
|
+
text: typeof value === "string" ? value : JSON.stringify(value),
|
|
108
|
+
encoding: typeof value === "string" ? "text" : "json"
|
|
109
|
+
} : {}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async function readSessionEventView(input, read) {
|
|
113
|
+
const { selection, continuation } = resolveSessionEventView(input);
|
|
114
|
+
const limit = Math.max(1, Math.min(50, input.limit ?? 10));
|
|
115
|
+
let after = continuation?.sequence && selection.direction === "after" ? continuation.sequence - 1 : selection.after;
|
|
116
|
+
let before = continuation?.sequence && selection.direction === "before" ? continuation.sequence + 1 : selection.before;
|
|
117
|
+
const events = [];
|
|
118
|
+
let hasMore = false;
|
|
119
|
+
let nextCursor = null;
|
|
120
|
+
let sourceExact = true;
|
|
121
|
+
let edge = null;
|
|
122
|
+
let legacyActive = continuation?.v === 1 && continuation.sequence !== null;
|
|
123
|
+
const page = () => ({
|
|
124
|
+
view: selection.view,
|
|
125
|
+
direction: selection.direction,
|
|
126
|
+
events,
|
|
127
|
+
nextAfter: selection.direction === "after" ? edge ?? selection.after : null,
|
|
128
|
+
nextBefore: selection.direction === "before" ? edge ?? selection.before : null,
|
|
129
|
+
hasMore,
|
|
130
|
+
nextCursor,
|
|
131
|
+
sourceExact,
|
|
132
|
+
...!sourceExact ? {
|
|
133
|
+
sourceLoss: {
|
|
134
|
+
reason: "structured_value_exceeds_budget",
|
|
135
|
+
completeTextAvailable: false,
|
|
136
|
+
message: "An oversized structured value was omitted. Scalar text remains retrievable through continuation; omitted structured values are not complete JSON results."
|
|
137
|
+
}
|
|
138
|
+
} : {},
|
|
139
|
+
maxBytes: SESSION_EVENT_VIEW_MAX_BYTES
|
|
140
|
+
});
|
|
141
|
+
const resume = (sequence, offset = 0) => {
|
|
142
|
+
hasMore = true;
|
|
143
|
+
nextCursor = encode(
|
|
144
|
+
{ ...selection, after, before },
|
|
145
|
+
sequence,
|
|
146
|
+
offset,
|
|
147
|
+
legacyActive && sequence === continuation?.sequence ? 1 : 2
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
for (let scan = 0; scan < 64; scan += 1) {
|
|
151
|
+
const source = await read({
|
|
152
|
+
after,
|
|
153
|
+
...before === null ? {} : { before },
|
|
154
|
+
direction: selection.direction,
|
|
155
|
+
limit: 8,
|
|
156
|
+
includeTypes: types[selection.view],
|
|
157
|
+
payloadMode: "full",
|
|
158
|
+
excludeUnclaimedHumanPrompts: true,
|
|
159
|
+
maxBytes: 1024 * 1024,
|
|
160
|
+
legacyUtf16: legacyActive,
|
|
161
|
+
view: selection.view,
|
|
162
|
+
includeArguments: selection.includeArguments,
|
|
163
|
+
includeOutput: selection.includeOutput,
|
|
164
|
+
...continuation?.sequence ? { sourceSequence: continuation.sequence, sourceOffset: continuation.offset } : {}
|
|
165
|
+
});
|
|
166
|
+
sourceExact &&= source.fullPayloadsExact;
|
|
167
|
+
const ordered = selection.direction === "before" ? [...source.events].reverse() : source.events;
|
|
168
|
+
for (const event of ordered) {
|
|
169
|
+
const slice = source.slices?.[event.sequence];
|
|
170
|
+
const item = project(event, selection);
|
|
171
|
+
if (item) {
|
|
172
|
+
const offset = continuation?.sequence === event.sequence ? continuation.offset : 0;
|
|
173
|
+
if (slice?.omitted) {
|
|
174
|
+
delete item.text;
|
|
175
|
+
item.sourceOmitted = { reason: "structured_value_exceeds_budget", complete: false };
|
|
176
|
+
}
|
|
177
|
+
const advance = (text) => slice?.unit === "codepoint" ? Array.from(text).length : text.length;
|
|
178
|
+
if (!slice && offset > (item.text?.length ?? 0))
|
|
179
|
+
throw new Error("Invalid message continuation offset");
|
|
180
|
+
if (!slice && offset > 0 && item.text && /[\uD800-\uDBFF]/.test(item.text[offset - 1]) && /[\uDC00-\uDFFF]/.test(item.text[offset] ?? "")) {
|
|
181
|
+
throw new Error("Invalid message continuation offset: splits a surrogate pair");
|
|
182
|
+
}
|
|
183
|
+
if (!slice && offset > 0 && item.text) item.text = item.text.slice(offset);
|
|
184
|
+
events.push(item);
|
|
185
|
+
if (bytes(page()) > SESSION_EVENT_VIEW_MAX_BYTES - 4096) {
|
|
186
|
+
events.pop();
|
|
187
|
+
if (events.length > 0) {
|
|
188
|
+
resume(event.sequence, offset);
|
|
189
|
+
if (selection.direction === "before") events.reverse();
|
|
190
|
+
return page();
|
|
191
|
+
}
|
|
192
|
+
if (!item.text) throw new Error("Session event identity exceeds page budget");
|
|
193
|
+
const text = item.text;
|
|
194
|
+
let low = 0;
|
|
195
|
+
let high = text.length;
|
|
196
|
+
while (low < high) {
|
|
197
|
+
const mid = Math.ceil((low + high) / 2);
|
|
198
|
+
if (bytes({ ...item, text: text.slice(0, mid) }) <= SESSION_EVENT_VIEW_MAX_BYTES - 6e3)
|
|
199
|
+
low = mid;
|
|
200
|
+
else high = mid - 1;
|
|
201
|
+
}
|
|
202
|
+
if (low > 0 && /[\uD800-\uDBFF]/.test(text[low - 1])) low -= 1;
|
|
203
|
+
if (low === 0) throw new Error("Session event identity exceeds page budget");
|
|
204
|
+
events.push({
|
|
205
|
+
...item,
|
|
206
|
+
text: text.slice(0, low),
|
|
207
|
+
fragment: {
|
|
208
|
+
offset,
|
|
209
|
+
nextOffset: offset + advance(text.slice(0, low)),
|
|
210
|
+
complete: false,
|
|
211
|
+
unit: slice?.unit ?? "utf16"
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
resume(event.sequence, offset + advance(text.slice(0, low)));
|
|
215
|
+
return page();
|
|
216
|
+
}
|
|
217
|
+
const nextOffset = offset + advance(item.text ?? "");
|
|
218
|
+
if (slice && !slice.omitted && nextOffset < slice.total) {
|
|
219
|
+
item.fragment = { offset, nextOffset, complete: false, unit: slice.unit };
|
|
220
|
+
resume(event.sequence, nextOffset);
|
|
221
|
+
if (selection.direction === "before") events.reverse();
|
|
222
|
+
return page();
|
|
223
|
+
}
|
|
224
|
+
if (offset > 0)
|
|
225
|
+
item.fragment = {
|
|
226
|
+
offset,
|
|
227
|
+
nextOffset,
|
|
228
|
+
complete: true,
|
|
229
|
+
unit: slice?.unit ?? "utf16"
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
edge = event.sequence;
|
|
233
|
+
legacyActive = false;
|
|
234
|
+
if (selection.direction === "after") after = event.sequence;
|
|
235
|
+
else before = event.sequence;
|
|
236
|
+
if (events.length >= limit) {
|
|
237
|
+
hasMore = source.hasMore || event !== ordered.at(-1);
|
|
238
|
+
nextCursor = hasMore ? encode({ ...selection, after, before }) : null;
|
|
239
|
+
if (selection.direction === "before") events.reverse();
|
|
240
|
+
return page();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (source.coveredSequence) {
|
|
244
|
+
if (selection.direction === "after") after = Math.max(after, source.coveredSequence.last);
|
|
245
|
+
else before = Math.min(before ?? Infinity, source.coveredSequence.first);
|
|
246
|
+
}
|
|
247
|
+
if (!source.hasMore) {
|
|
248
|
+
hasMore = false;
|
|
249
|
+
nextCursor = null;
|
|
250
|
+
if (selection.direction === "before") events.reverse();
|
|
251
|
+
return page();
|
|
252
|
+
}
|
|
253
|
+
hasMore = true;
|
|
254
|
+
nextCursor = encode({ ...selection, after, before });
|
|
255
|
+
}
|
|
256
|
+
if (selection.direction === "before") events.reverse();
|
|
257
|
+
return page();
|
|
258
|
+
}
|
|
259
|
+
export {
|
|
260
|
+
SESSION_EVENT_VIEW_MAX_BYTES,
|
|
261
|
+
readSessionEventView,
|
|
262
|
+
resolveSessionEventView
|
|
263
|
+
};
|
|
264
|
+
//# sourceMappingURL=session-event-view-MU3HMNV3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/session-event-view.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { SessionEvent, SessionEventType } from \"@opengeni/contracts\";\nimport type {\n SessionEventSliceOptions,\n SessionEventSlicePage,\n} from \"@opengeni/db/session-event-slices\";\n\nexport const SESSION_EVENT_VIEW_MAX_BYTES = 16 * 1024;\nconst selectionSchema = z.object({\n sessionId: z.string().uuid(),\n view: z.enum([\"conversation\", \"results\", \"tools\"]),\n includeArguments: z.boolean(),\n includeOutput: z.boolean(),\n callId: z\n .string()\n .max(512)\n .refine(\n (value) => Buffer.byteLength(JSON.stringify(value), \"utf8\") <= 2048,\n \"callId exceeds the encoded cursor budget\",\n )\n .nullable(),\n direction: z.enum([\"before\", \"after\"]),\n after: z.number().int().nonnegative(),\n before: z.number().int().positive().nullable(),\n});\nconst cursorSchema = z.object({\n v: z.union([z.literal(1), z.literal(2)]),\n selection: selectionSchema,\n sequence: z.number().int().positive().nullable(),\n offset: z.number().int().nonnegative().max(2_147_483_647),\n});\ntype Selection = z.infer<typeof selectionSchema>;\nexport type SessionEventViewInput = {\n sessionId: string;\n view?: Selection[\"view\"] | undefined;\n after?: number | undefined;\n before?: number | undefined;\n direction?: Selection[\"direction\"] | undefined;\n limit?: number | undefined;\n cursor?: string | undefined;\n callId?: string | undefined;\n includeArguments?: boolean | undefined;\n includeOutput?: boolean | undefined;\n};\ntype Item = { sequence: number; turnId?: string; role?: string; text?: string } & Record<\n string,\n unknown\n>;\ntype ReadPage = (options: SessionEventSliceOptions) => Promise<SessionEventSlicePage>;\nconst types: Record<Selection[\"view\"], SessionEventType[]> = {\n conversation: [\"user.message\", \"agent.message.completed\"],\n // Final turn output is authoritative: do not repeat message.completed text.\n results: [\"turn.completed\", \"turn.failed\", \"goal.completed\", \"goal.paused\", \"tool.auth_needed\"],\n tools: [\"agent.toolCall.created\", \"agent.toolCall.output\"],\n};\nconst record = (value: unknown): Record<string, unknown> =>\n value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\nconst bytes = (value: unknown) => Buffer.byteLength(JSON.stringify(value, null, 2), \"utf8\");\nconst encode = (selection: Selection, sequence: number | null = null, offset = 0, v = 2) =>\n Buffer.from(JSON.stringify({ v, selection, sequence, offset })).toString(\"base64url\");\n\n/** A cursor is a bounded selector, never authority. The caller reauthorizes every read. */\nexport function resolveSessionEventView(input: SessionEventViewInput) {\n let continuation: z.infer<typeof cursorSchema> | null = null;\n if (input.cursor !== undefined) {\n if (input.cursor.length > 4096)\n throw new Error(\"session_events cursor exceeds 4096 characters\");\n try {\n continuation = cursorSchema.parse(\n JSON.parse(Buffer.from(input.cursor, \"base64url\").toString()),\n );\n } catch {\n throw new Error(\"Invalid session_events cursor\");\n }\n const previous = continuation.selection;\n for (const key of [\n \"sessionId\",\n \"view\",\n \"includeArguments\",\n \"includeOutput\",\n \"callId\",\n \"direction\",\n \"after\",\n \"before\",\n ] as const) {\n if (input[key] !== undefined && input[key] !== previous[key]) {\n throw new Error(`session_events cursor cannot change ${key}`);\n }\n }\n }\n const selection =\n continuation?.selection ??\n selectionSchema.parse({\n sessionId: input.sessionId,\n view: input.view ?? \"conversation\",\n includeArguments: input.includeArguments ?? false,\n includeOutput: input.includeOutput ?? false,\n callId: input.callId ?? null,\n direction:\n input.direction ??\n (input.before !== undefined || input.after === undefined ? \"before\" : \"after\"),\n after: input.after ?? 0,\n before: input.before ?? null,\n });\n if (\n selection.view !== \"tools\" &&\n (selection.callId || selection.includeArguments || selection.includeOutput)\n ) {\n throw new Error(\"callId/includeArguments/includeOutput require view=tools\");\n }\n if (\n continuation &&\n ((continuation.sequence === null && continuation.offset !== 0) ||\n (continuation.sequence !== null &&\n (continuation.sequence <= selection.after ||\n (selection.before !== null && continuation.sequence >= selection.before))))\n )\n throw new Error(\"Invalid session_events cursor position\");\n return { selection, continuation };\n}\n\nfunction project(event: SessionEvent, selection: Selection): Item | null {\n if (event.duplicateOfEventId || (event.turnAssociation && event.turnAssociation !== \"current\"))\n return null;\n const p = record(event.payload);\n const base = { sequence: event.sequence, ...(event.turnId ? { turnId: event.turnId } : {}) };\n if (selection.view === \"conversation\") {\n return typeof p.text === \"string\" && p.text.length > 0\n ? { ...base, role: event.type === \"user.message\" ? \"user\" : \"assistant\", text: p.text }\n : null;\n }\n if (selection.view === \"results\") {\n if (event.type === \"turn.completed\" && (\"maintenance\" in p || \"segmentLimit\" in p)) return null;\n const value = event.type === \"turn.completed\" ? (p.output ?? p.result) : p;\n if (value === undefined || value === \"\") return null;\n return {\n ...base,\n type: event.type,\n text: typeof value === \"string\" ? value : JSON.stringify(value),\n };\n }\n const callId = p.callId ?? p.call_id ?? p.id;\n if (selection.callId !== null && selection.callId !== callId) return null;\n const output = event.type === \"agent.toolCall.output\";\n // Choose one canonical slot. Never ship the raw receipt beside its parsed copy.\n const value = output ? p.output : (p.arguments ?? p.args);\n return {\n ...base,\n callId,\n kind: output ? \"result\" : \"call\",\n ...(typeof p.name === \"string\" ? { name: p.name } : {}),\n ...(p.identityOmitted === true ? { identityOmitted: true } : {}),\n ...(p.isError === true || record(value).isError === true ? { isError: true } : {}),\n ...((output ? selection.includeOutput : selection.includeArguments) && value !== undefined\n ? {\n text: typeof value === \"string\" ? value : JSON.stringify(value),\n encoding: typeof value === \"string\" ? \"text\" : \"json\",\n }\n : {}),\n };\n}\n\n/** Read-only projection over the existing RLS/audit query. No command observations. */\nexport async function readSessionEventView(input: SessionEventViewInput, read: ReadPage) {\n const { selection, continuation } = resolveSessionEventView(input);\n const limit = Math.max(1, Math.min(50, input.limit ?? 10));\n let after =\n continuation?.sequence && selection.direction === \"after\"\n ? continuation.sequence - 1\n : selection.after;\n let before =\n continuation?.sequence && selection.direction === \"before\"\n ? continuation.sequence + 1\n : selection.before;\n const events: Item[] = [];\n let hasMore = false;\n let nextCursor: string | null = null;\n let sourceExact = true;\n let edge: number | null = null;\n let legacyActive = continuation?.v === 1 && continuation.sequence !== null;\n const page = () => ({\n view: selection.view,\n direction: selection.direction,\n events,\n nextAfter: selection.direction === \"after\" ? (edge ?? selection.after) : null,\n nextBefore: selection.direction === \"before\" ? (edge ?? selection.before) : null,\n hasMore,\n nextCursor,\n sourceExact,\n ...(!sourceExact\n ? {\n sourceLoss: {\n reason: \"structured_value_exceeds_budget\" as const,\n completeTextAvailable: false as const,\n message:\n \"An oversized structured value was omitted. Scalar text remains retrievable through continuation; omitted structured values are not complete JSON results.\",\n },\n }\n : {}),\n maxBytes: SESSION_EVENT_VIEW_MAX_BYTES,\n });\n const resume = (sequence: number, offset = 0) => {\n hasMore = true;\n nextCursor = encode(\n { ...selection, after, before },\n sequence,\n offset,\n legacyActive && sequence === continuation?.sequence ? 1 : 2,\n );\n };\n // Bound work even when a sparse exact callId lookup matches nothing. The\n // returned cursor advances the scan without claiming the lookup is exhausted.\n for (let scan = 0; scan < 64; scan += 1) {\n const source = await read({\n after,\n ...(before === null ? {} : { before }),\n direction: selection.direction,\n limit: 8,\n includeTypes: types[selection.view],\n payloadMode: \"full\",\n excludeUnclaimedHumanPrompts: true,\n maxBytes: 1024 * 1024,\n legacyUtf16: legacyActive,\n view: selection.view,\n includeArguments: selection.includeArguments,\n includeOutput: selection.includeOutput,\n ...(continuation?.sequence\n ? { sourceSequence: continuation.sequence, sourceOffset: continuation.offset }\n : {}),\n });\n sourceExact &&= source.fullPayloadsExact;\n const ordered = selection.direction === \"before\" ? [...source.events].reverse() : source.events;\n for (const event of ordered) {\n const slice = source.slices?.[event.sequence];\n const item = project(event, selection);\n if (item) {\n const offset = continuation?.sequence === event.sequence ? continuation.offset : 0;\n if (slice?.omitted) {\n delete item.text;\n item.sourceOmitted = { reason: \"structured_value_exceeds_budget\", complete: false };\n }\n const advance = (text: string) =>\n slice?.unit === \"codepoint\" ? Array.from(text).length : text.length;\n if (!slice && offset > (item.text?.length ?? 0))\n throw new Error(\"Invalid message continuation offset\");\n if (\n !slice &&\n offset > 0 &&\n item.text &&\n /[\\uD800-\\uDBFF]/.test(item.text[offset - 1]!) &&\n /[\\uDC00-\\uDFFF]/.test(item.text[offset] ?? \"\")\n ) {\n throw new Error(\"Invalid message continuation offset: splits a surrogate pair\");\n }\n if (!slice && offset > 0 && item.text) item.text = item.text.slice(offset);\n events.push(item);\n // Reserve enough for the bounded cursor and fragment facts.\n if (bytes(page()) > SESSION_EVENT_VIEW_MAX_BYTES - 4096) {\n events.pop();\n if (events.length > 0) {\n resume(event.sequence, offset);\n if (selection.direction === \"before\") events.reverse();\n return page();\n }\n if (!item.text) throw new Error(\"Session event identity exceeds page budget\");\n const text = item.text;\n let low = 0;\n let high = text.length;\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n if (bytes({ ...item, text: text.slice(0, mid) }) <= SESSION_EVENT_VIEW_MAX_BYTES - 6000)\n low = mid;\n else high = mid - 1;\n }\n // Do not split a UTF-16 surrogate pair (UTF-8 remains lossless).\n if (low > 0 && /[\\uD800-\\uDBFF]/.test(text[low - 1]!)) low -= 1;\n if (low === 0) throw new Error(\"Session event identity exceeds page budget\");\n events.push({\n ...item,\n text: text.slice(0, low),\n fragment: {\n offset,\n nextOffset: offset + advance(text.slice(0, low)),\n complete: false,\n unit: slice?.unit ?? \"utf16\",\n },\n });\n resume(event.sequence, offset + advance(text.slice(0, low)));\n return page();\n }\n const nextOffset = offset + advance(item.text ?? \"\");\n if (slice && !slice.omitted && nextOffset < slice.total) {\n item.fragment = { offset, nextOffset, complete: false, unit: slice.unit };\n resume(event.sequence, nextOffset);\n if (selection.direction === \"before\") events.reverse();\n return page();\n }\n if (offset > 0)\n item.fragment = {\n offset,\n nextOffset,\n complete: true,\n unit: slice?.unit ?? \"utf16\",\n };\n }\n edge = event.sequence;\n legacyActive = false;\n if (selection.direction === \"after\") after = event.sequence;\n else before = event.sequence;\n if (events.length >= limit) {\n hasMore = source.hasMore || event !== ordered.at(-1);\n nextCursor = hasMore ? encode({ ...selection, after, before }) : null;\n if (selection.direction === \"before\") events.reverse();\n return page();\n }\n }\n // Metadata selection can advance over stale/duplicate rows without a\n // projected payload. Use its covered edge rather than repeating the page.\n if (source.coveredSequence) {\n if (selection.direction === \"after\") after = Math.max(after, source.coveredSequence.last);\n else before = Math.min(before ?? Infinity, source.coveredSequence.first);\n }\n if (!source.hasMore) {\n hasMore = false;\n nextCursor = null;\n if (selection.direction === \"before\") events.reverse();\n return page();\n }\n hasMore = true;\n nextCursor = encode({ ...selection, after, before });\n }\n if (selection.direction === \"before\") events.reverse();\n return page();\n}\n"],"mappings":"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","names":["value"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type AccessGrant } from "@opengeni/contracts";
|
|
2
|
+
import type { ApiRouteDeps, ObjectStorageDependency } from "@opengeni/core";
|
|
3
|
+
import { prepareWorkspaceArtifactContent, type PreparedWorkspaceArtifactContent } from "./workspace-artifact-content.js";
|
|
4
|
+
type Storage = NonNullable<ObjectStorageDependency>;
|
|
5
|
+
export declare const MAX_SITE_SOURCE_BYTES: number;
|
|
6
|
+
export declare function validateSiteSource(storage: Storage, key: string, sizeBytes: number): Promise<void>;
|
|
7
|
+
export declare function prepareWorkspaceArtifactUpload(deps: ApiRouteDeps, grant: AccessGrant): Promise<{
|
|
8
|
+
uploadId: string;
|
|
9
|
+
html: {
|
|
10
|
+
putUrl: string;
|
|
11
|
+
requiredHeaders: Record<string, string>;
|
|
12
|
+
};
|
|
13
|
+
source: {
|
|
14
|
+
putUrl: string;
|
|
15
|
+
requiredHeaders: Record<string, string>;
|
|
16
|
+
};
|
|
17
|
+
expiresAt: string;
|
|
18
|
+
}>;
|
|
19
|
+
/** Provider version-pinned reads, without Site SHA checks or full HTML buffering. */
|
|
20
|
+
export declare function readArtifactObject(storage: Storage, key: string, expectedHead?: Awaited<ReturnType<NonNullable<Storage["headObject"]>>>): AsyncGenerator<Uint8Array<ArrayBufferLike>, void, unknown>;
|
|
21
|
+
type Input = Partial<Parameters<typeof prepareWorkspaceArtifactContent>[2]> & {
|
|
22
|
+
uploadId?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function prepareWorkspaceArtifactPublication(deps: ApiRouteDeps, grant: AccessGrant, input: Input): Promise<PreparedWorkspaceArtifactContent & {
|
|
25
|
+
uploadId?: string;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function workspaceArtifactDownloads(storage: Storage, ref: {
|
|
28
|
+
contentKey: string;
|
|
29
|
+
sourceKey: string | null;
|
|
30
|
+
}, audience: "sandbox" | "public"): Promise<{
|
|
31
|
+
html: {
|
|
32
|
+
url: string;
|
|
33
|
+
expiresAt: Date;
|
|
34
|
+
};
|
|
35
|
+
source: {
|
|
36
|
+
url: string;
|
|
37
|
+
expiresAt: Date;
|
|
38
|
+
format: string;
|
|
39
|
+
} | null;
|
|
40
|
+
}>;
|
|
41
|
+
export {};
|
|
@@ -2,11 +2,11 @@ import { type ToolGatewayIdentity, type WorkspaceArtifactSourceBundle as Workspa
|
|
|
2
2
|
import type { ObjectStorageDependency } from "@opengeni/core";
|
|
3
3
|
export type PreparedWorkspaceArtifactContent = {
|
|
4
4
|
contentKey: string;
|
|
5
|
-
contentSha256:
|
|
5
|
+
contentSha256: null;
|
|
6
6
|
sizeBytes: number;
|
|
7
|
-
sourceKey: string;
|
|
8
|
-
sourceSha256:
|
|
9
|
-
sourceSizeBytes: number;
|
|
7
|
+
sourceKey: string | null;
|
|
8
|
+
sourceSha256: null;
|
|
9
|
+
sourceSizeBytes: number | null;
|
|
10
10
|
requestedTools?: ToolGatewayIdentity[];
|
|
11
11
|
persistContent: () => Promise<void>;
|
|
12
12
|
discardContent: () => Promise<void>;
|