@percena/weft 0.4.0-next.3 → 0.4.0-next.5
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/action-bridge.cjs +172 -6
- package/dist/action-bridge.d.cts +112 -13
- package/dist/action-bridge.d.ts +112 -13
- package/dist/action-bridge.js +166 -4
- package/dist/chat.cjs +982 -3
- package/dist/chat.d.cts +30 -1
- package/dist/chat.d.ts +30 -1
- package/dist/chat.js +981 -2
- package/dist/index.cjs +341 -1616
- package/dist/index.d.cts +4 -274
- package/dist/index.d.ts +4 -274
- package/dist/index.js +174 -1408
- package/dist/styles/fonts/KaTeX_AMS-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_AMS-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- package/dist/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- package/dist/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Main-Bold.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Main-Bold.woff +0 -0
- package/dist/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- package/dist/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Main-Italic.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Main-Italic.woff +0 -0
- package/dist/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Main-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Main-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- package/dist/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Math-Italic.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Math-Italic.woff +0 -0
- package/dist/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Script-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Script-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Size1-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Size1-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Size2-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Size2-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Size3-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Size3-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Size4-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Size4-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/dist/styles/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- package/dist/styles/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- package/dist/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/package.json +2 -30
- package/dist/local-runtime.cjs +0 -1387
- package/dist/local-runtime.d.cts +0 -3314
- package/dist/local-runtime.d.ts +0 -3314
- package/dist/local-runtime.js +0 -1345
- package/dist/skills-browser.cjs +0 -118
- package/dist/skills-browser.d.cts +0 -105
- package/dist/skills-browser.d.ts +0 -105
- package/dist/skills-browser.js +0 -88
package/dist/chat.js
CHANGED
|
@@ -7043,6 +7043,27 @@ import { useState as useState22 } from "react";
|
|
|
7043
7043
|
import { useCallback as useCallback9, useEffect as useEffect9, useMemo as useMemo8, useRef as useRef8, useState as useState12 } from "react";
|
|
7044
7044
|
|
|
7045
7045
|
// ../packages/timeline/dist/index.js
|
|
7046
|
+
function createTimelineCursor(cursor) {
|
|
7047
|
+
return {
|
|
7048
|
+
epoch: cursor.epoch,
|
|
7049
|
+
afterSeq: cursor.afterSeq
|
|
7050
|
+
};
|
|
7051
|
+
}
|
|
7052
|
+
function fetchTimeline(timeline, request = {}) {
|
|
7053
|
+
const ordered = sortTimeline(timeline);
|
|
7054
|
+
const cursor = request.cursor ?? cursorFromTimelineStart(ordered);
|
|
7055
|
+
const items = ordered.filter((item) => item.epoch === cursor.epoch && item.seq > cursor.afterSeq).slice(0, request.limit);
|
|
7056
|
+
const lastSeq = items.at(-1)?.seq ?? cursor.afterSeq;
|
|
7057
|
+
const firstSeq = items[0]?.seq;
|
|
7058
|
+
return {
|
|
7059
|
+
items,
|
|
7060
|
+
nextCursor: {
|
|
7061
|
+
epoch: cursor.epoch,
|
|
7062
|
+
afterSeq: lastSeq
|
|
7063
|
+
},
|
|
7064
|
+
hasGap: firstSeq !== void 0 && firstSeq > cursor.afterSeq + 1
|
|
7065
|
+
};
|
|
7066
|
+
}
|
|
7046
7067
|
function mergeTimeline(existing, incoming) {
|
|
7047
7068
|
const byKey = /* @__PURE__ */ new Map();
|
|
7048
7069
|
for (const item of [...existing, ...incoming]) {
|
|
@@ -7050,6 +7071,12 @@ function mergeTimeline(existing, incoming) {
|
|
|
7050
7071
|
}
|
|
7051
7072
|
return sortTimeline([...byKey.values()]);
|
|
7052
7073
|
}
|
|
7074
|
+
function cursorFromTimelineStart(timeline) {
|
|
7075
|
+
return {
|
|
7076
|
+
epoch: timeline[0]?.epoch ?? "default",
|
|
7077
|
+
afterSeq: 0
|
|
7078
|
+
};
|
|
7079
|
+
}
|
|
7053
7080
|
function sortTimeline(timeline) {
|
|
7054
7081
|
return [...timeline].sort((left, right) => {
|
|
7055
7082
|
if (left.epoch !== right.epoch) return left.epoch.localeCompare(right.epoch);
|
|
@@ -7823,8 +7850,960 @@ function TimelineAgentChatPanel({
|
|
|
7823
7850
|
] });
|
|
7824
7851
|
}
|
|
7825
7852
|
|
|
7826
|
-
// src/
|
|
7827
|
-
import {
|
|
7853
|
+
// ../packages/react/src/use-agent-session.ts
|
|
7854
|
+
import { useEffect as useEffect10, useMemo as useMemo9, useRef as useRef9 } from "react";
|
|
7855
|
+
|
|
7856
|
+
// ../packages/runtime-core/dist/index.js
|
|
7857
|
+
var RUNTIME_KINDS = ["native-sdk", "app-server", "compatible-sdk", "cli-fallback"];
|
|
7858
|
+
var initialRuntimeState = {
|
|
7859
|
+
status: "idle",
|
|
7860
|
+
acceptedMessages: [],
|
|
7861
|
+
queuedMessages: []
|
|
7862
|
+
};
|
|
7863
|
+
function reduceRuntimeState(state = initialRuntimeState, action) {
|
|
7864
|
+
switch (action.type) {
|
|
7865
|
+
case "preflight_start":
|
|
7866
|
+
return { ...state, status: "preflighting", lastError: void 0 };
|
|
7867
|
+
case "preflight_ok":
|
|
7868
|
+
return { ...state, status: "ready", lastError: void 0 };
|
|
7869
|
+
case "preflight_error":
|
|
7870
|
+
return { ...state, status: "failed", lastError: action.error };
|
|
7871
|
+
case "starting":
|
|
7872
|
+
if (state.status === "ready" || state.status === "idle") {
|
|
7873
|
+
return { ...state, status: "starting" };
|
|
7874
|
+
}
|
|
7875
|
+
return state;
|
|
7876
|
+
case "send_message":
|
|
7877
|
+
if (state.status === "running" || state.status === "waiting_for_permission") {
|
|
7878
|
+
return {
|
|
7879
|
+
...state,
|
|
7880
|
+
queuedMessages: [...state.queuedMessages, action.message]
|
|
7881
|
+
};
|
|
7882
|
+
}
|
|
7883
|
+
return {
|
|
7884
|
+
...state,
|
|
7885
|
+
status: "running",
|
|
7886
|
+
acceptedMessages: [...state.acceptedMessages, action.message]
|
|
7887
|
+
};
|
|
7888
|
+
case "permission_request":
|
|
7889
|
+
return {
|
|
7890
|
+
...state,
|
|
7891
|
+
status: "waiting_for_permission",
|
|
7892
|
+
waitingPermissionRequestId: action.requestId
|
|
7893
|
+
};
|
|
7894
|
+
case "permission_response":
|
|
7895
|
+
return {
|
|
7896
|
+
...state,
|
|
7897
|
+
status: "running",
|
|
7898
|
+
waitingPermissionRequestId: void 0
|
|
7899
|
+
};
|
|
7900
|
+
case "turn_completed":
|
|
7901
|
+
if (state.status === "running") {
|
|
7902
|
+
return { ...state, status: "turn_completed" };
|
|
7903
|
+
}
|
|
7904
|
+
return state;
|
|
7905
|
+
case "complete": {
|
|
7906
|
+
if (state.status === "turn_completed") {
|
|
7907
|
+
const [nextMessage2, ...remaining2] = state.queuedMessages;
|
|
7908
|
+
if (nextMessage2) {
|
|
7909
|
+
return {
|
|
7910
|
+
...state,
|
|
7911
|
+
status: "running",
|
|
7912
|
+
acceptedMessages: [...state.acceptedMessages, nextMessage2],
|
|
7913
|
+
queuedMessages: remaining2
|
|
7914
|
+
};
|
|
7915
|
+
}
|
|
7916
|
+
return { ...state, status: "ready" };
|
|
7917
|
+
}
|
|
7918
|
+
const [nextMessage, ...remaining] = state.queuedMessages;
|
|
7919
|
+
if (nextMessage) {
|
|
7920
|
+
return {
|
|
7921
|
+
...state,
|
|
7922
|
+
status: "running",
|
|
7923
|
+
acceptedMessages: [...state.acceptedMessages, nextMessage],
|
|
7924
|
+
queuedMessages: remaining
|
|
7925
|
+
};
|
|
7926
|
+
}
|
|
7927
|
+
return { ...state, status: "ready" };
|
|
7928
|
+
}
|
|
7929
|
+
case "abort":
|
|
7930
|
+
return {
|
|
7931
|
+
...state,
|
|
7932
|
+
status: "ready",
|
|
7933
|
+
lastError: action.reason,
|
|
7934
|
+
queuedMessages: [],
|
|
7935
|
+
waitingPermissionRequestId: void 0
|
|
7936
|
+
};
|
|
7937
|
+
case "error":
|
|
7938
|
+
return { ...state, status: "failed", lastError: action.error };
|
|
7939
|
+
case "dispose":
|
|
7940
|
+
return {
|
|
7941
|
+
...state,
|
|
7942
|
+
status: "disposed",
|
|
7943
|
+
queuedMessages: [],
|
|
7944
|
+
waitingPermissionRequestId: void 0
|
|
7945
|
+
};
|
|
7946
|
+
}
|
|
7947
|
+
}
|
|
7948
|
+
function createRuntimeExtensionContext(context = {}) {
|
|
7949
|
+
return {
|
|
7950
|
+
policy: context.policy,
|
|
7951
|
+
sources: context.sources ? { enabledSourceSlugs: unique(context.sources.enabledSourceSlugs) } : void 0,
|
|
7952
|
+
skills: context.skills ? { activeSkillSlugs: unique(context.skills.activeSkillSlugs) } : void 0,
|
|
7953
|
+
commandOrigin: context.commandOrigin,
|
|
7954
|
+
hostServices: context.hostServices
|
|
7955
|
+
};
|
|
7956
|
+
}
|
|
7957
|
+
function unique(values) {
|
|
7958
|
+
return [...new Set(values)];
|
|
7959
|
+
}
|
|
7960
|
+
function findCandidate(candidates, kind) {
|
|
7961
|
+
return candidates.find((candidate) => candidate.kind === kind);
|
|
7962
|
+
}
|
|
7963
|
+
function defaultRuntimeKindOrder(provider) {
|
|
7964
|
+
if (provider === "codex") {
|
|
7965
|
+
return ["app-server", "native-sdk", "compatible-sdk", "cli-fallback"];
|
|
7966
|
+
}
|
|
7967
|
+
return RUNTIME_KINDS;
|
|
7968
|
+
}
|
|
7969
|
+
function firstAvailableCandidate(candidates, provider) {
|
|
7970
|
+
for (const kind of defaultRuntimeKindOrder(provider)) {
|
|
7971
|
+
const candidate = findCandidate(candidates, kind);
|
|
7972
|
+
if (candidate?.available) return candidate;
|
|
7973
|
+
}
|
|
7974
|
+
return void 0;
|
|
7975
|
+
}
|
|
7976
|
+
function selectRuntimeCandidate(options) {
|
|
7977
|
+
const preferred = options.preferredRuntime ? findCandidate(options.candidates, options.preferredRuntime) : void 0;
|
|
7978
|
+
if (preferred?.available) {
|
|
7979
|
+
return { selected: preferred.kind, fallback: false };
|
|
7980
|
+
}
|
|
7981
|
+
if (preferred && options.allowFallback !== true) {
|
|
7982
|
+
return {
|
|
7983
|
+
fallback: false,
|
|
7984
|
+
error: preferred.reason ?? `${preferred.kind} runtime is unavailable`
|
|
7985
|
+
};
|
|
7986
|
+
}
|
|
7987
|
+
const selected = firstAvailableCandidate(options.candidates, options.provider);
|
|
7988
|
+
if (!selected) {
|
|
7989
|
+
return {
|
|
7990
|
+
fallback: false,
|
|
7991
|
+
error: options.candidates.map((candidate) => candidate.reason).filter(Boolean).join("; ") || "No runtime candidates are available"
|
|
7992
|
+
};
|
|
7993
|
+
}
|
|
7994
|
+
const fallback = Boolean(preferred && selected.kind !== preferred.kind);
|
|
7995
|
+
return {
|
|
7996
|
+
selected: selected.kind,
|
|
7997
|
+
fallback,
|
|
7998
|
+
fallbackReason: fallback ? preferred?.reason ?? `${preferred?.kind ?? "preferred"} runtime is unavailable` : void 0
|
|
7999
|
+
};
|
|
8000
|
+
}
|
|
8001
|
+
function createRuntimeCapabilityReport(options) {
|
|
8002
|
+
const selection = selectRuntimeCandidate(options);
|
|
8003
|
+
const extensionCapabilities = normalizeExtensionCapabilities(options.extensionCapabilities);
|
|
8004
|
+
return {
|
|
8005
|
+
provider: options.provider,
|
|
8006
|
+
candidates: options.candidates,
|
|
8007
|
+
preferredRuntime: options.preferredRuntime,
|
|
8008
|
+
allowFallback: options.allowFallback === true,
|
|
8009
|
+
auth: options.auth,
|
|
8010
|
+
...extensionCapabilities,
|
|
8011
|
+
...selection
|
|
8012
|
+
};
|
|
8013
|
+
}
|
|
8014
|
+
function normalizeExtensionCapabilities(capabilities = {}) {
|
|
8015
|
+
return {
|
|
8016
|
+
policyCapabilities: capabilities.policy ?? {
|
|
8017
|
+
supported: false,
|
|
8018
|
+
modes: [],
|
|
8019
|
+
approvals: false,
|
|
8020
|
+
toolPolicy: false
|
|
8021
|
+
},
|
|
8022
|
+
sourceCapabilities: capabilities.sources ?? {
|
|
8023
|
+
supported: false
|
|
8024
|
+
},
|
|
8025
|
+
skillCapabilities: capabilities.skills ?? {
|
|
8026
|
+
supported: false
|
|
8027
|
+
},
|
|
8028
|
+
automationCapabilities: capabilities.automations ?? {
|
|
8029
|
+
supported: false,
|
|
8030
|
+
eventBus: false,
|
|
8031
|
+
schedulerHost: false,
|
|
8032
|
+
promptAction: false,
|
|
8033
|
+
webhookAction: false
|
|
8034
|
+
},
|
|
8035
|
+
hostToolCapabilities: capabilities.hostTools ?? {
|
|
8036
|
+
supported: false,
|
|
8037
|
+
sessionTools: false,
|
|
8038
|
+
workflowTransitions: false,
|
|
8039
|
+
browserActions: false,
|
|
8040
|
+
metadataWrites: false
|
|
8041
|
+
}
|
|
8042
|
+
};
|
|
8043
|
+
}
|
|
8044
|
+
|
|
8045
|
+
// ../packages/client/dist/index.js
|
|
8046
|
+
var FlitroHttpClient = class {
|
|
8047
|
+
baseUrl;
|
|
8048
|
+
timeout;
|
|
8049
|
+
apiKey;
|
|
8050
|
+
tenantId;
|
|
8051
|
+
onTokenExpired;
|
|
8052
|
+
token;
|
|
8053
|
+
constructor(options) {
|
|
8054
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
8055
|
+
this.timeout = options.timeout ?? 3e4;
|
|
8056
|
+
this.apiKey = options.apiKey ?? "";
|
|
8057
|
+
this.tenantId = options.tenantId ?? "";
|
|
8058
|
+
this.token = options.token ?? "";
|
|
8059
|
+
this.onTokenExpired = options.onTokenExpired;
|
|
8060
|
+
}
|
|
8061
|
+
/** Current Authorization bearer (scoped token wins over apiKey). */
|
|
8062
|
+
getBearerToken() {
|
|
8063
|
+
return this.token || this.apiKey;
|
|
8064
|
+
}
|
|
8065
|
+
/** Replace the scoped token (e.g. after a host-backend refresh). */
|
|
8066
|
+
setToken(token) {
|
|
8067
|
+
this.token = token;
|
|
8068
|
+
}
|
|
8069
|
+
buildHeaders() {
|
|
8070
|
+
const headers = { "Content-Type": "application/json" };
|
|
8071
|
+
const bearer = this.getBearerToken();
|
|
8072
|
+
if (bearer) headers["Authorization"] = `Bearer ${bearer}`;
|
|
8073
|
+
if (!this.token && this.tenantId) headers["X-Tenant-ID"] = this.tenantId;
|
|
8074
|
+
return headers;
|
|
8075
|
+
}
|
|
8076
|
+
async preflight() {
|
|
8077
|
+
return this.get("/v1/capabilities");
|
|
8078
|
+
}
|
|
8079
|
+
async health() {
|
|
8080
|
+
return this.get("/v1/health");
|
|
8081
|
+
}
|
|
8082
|
+
async createSession(options) {
|
|
8083
|
+
return this.post("/v1/sessions", {
|
|
8084
|
+
title: options?.title ?? "Weft session",
|
|
8085
|
+
model: options?.model,
|
|
8086
|
+
skill_names: options?.skillNames,
|
|
8087
|
+
mcp_server_names: options?.mcpServerNames
|
|
8088
|
+
});
|
|
8089
|
+
}
|
|
8090
|
+
async getSession(sessionId) {
|
|
8091
|
+
return this.get(`/v1/sessions/${encodeURIComponent(sessionId)}`);
|
|
8092
|
+
}
|
|
8093
|
+
async sendMessage(sessionId, message, options) {
|
|
8094
|
+
const budget = options?.budget ? {
|
|
8095
|
+
max_steps: options.budget.maxSteps,
|
|
8096
|
+
max_tokens: options.budget.maxTokens,
|
|
8097
|
+
max_wall_time_sec: options.budget.maxWallTimeSec
|
|
8098
|
+
} : void 0;
|
|
8099
|
+
return this.post(`/v1/sessions/${encodeURIComponent(sessionId)}/runs`, {
|
|
8100
|
+
message,
|
|
8101
|
+
model: options?.model,
|
|
8102
|
+
skill_names: options?.skillNames,
|
|
8103
|
+
mcp_server_names: options?.mcpServerNames,
|
|
8104
|
+
tool_names: options?.toolNames,
|
|
8105
|
+
approval_policy: options?.approvalPolicy,
|
|
8106
|
+
execution_mode: options?.executionMode,
|
|
8107
|
+
workspace_id: options?.workspaceId,
|
|
8108
|
+
budget
|
|
8109
|
+
});
|
|
8110
|
+
}
|
|
8111
|
+
async cancelRun(runId) {
|
|
8112
|
+
return this.post(`/v1/runs/${encodeURIComponent(runId)}/cancel`, {});
|
|
8113
|
+
}
|
|
8114
|
+
async resumeTool(runId, resumeData) {
|
|
8115
|
+
return this.post(
|
|
8116
|
+
`/v1/runs/${encodeURIComponent(runId)}/resume-tool`,
|
|
8117
|
+
{ resume_data: resumeData }
|
|
8118
|
+
);
|
|
8119
|
+
}
|
|
8120
|
+
async respondToPermission(sessionId, requestId, allowed, options) {
|
|
8121
|
+
return this.post(
|
|
8122
|
+
`/v1/sessions/${encodeURIComponent(sessionId)}/permission-response`,
|
|
8123
|
+
{ requestId, allowed, remember: options?.remember, text: options?.text, answer: options?.answer }
|
|
8124
|
+
);
|
|
8125
|
+
}
|
|
8126
|
+
async patchSession(sessionId, patch) {
|
|
8127
|
+
return this.patch(
|
|
8128
|
+
`/v1/sessions/${encodeURIComponent(sessionId)}`,
|
|
8129
|
+
patch
|
|
8130
|
+
);
|
|
8131
|
+
}
|
|
8132
|
+
async listModels() {
|
|
8133
|
+
return this.get("/v1/models");
|
|
8134
|
+
}
|
|
8135
|
+
async fetchTimeline(sessionId, afterSeq, limit) {
|
|
8136
|
+
const params = new URLSearchParams();
|
|
8137
|
+
if (afterSeq !== void 0) params.set("after_seq", String(afterSeq));
|
|
8138
|
+
if (limit !== void 0) params.set("limit", String(limit));
|
|
8139
|
+
const qs = params.toString();
|
|
8140
|
+
const url = `/v1/sessions/${encodeURIComponent(sessionId)}/timeline/fetch${qs ? `?${qs}` : ""}`;
|
|
8141
|
+
return this.get(url);
|
|
8142
|
+
}
|
|
8143
|
+
/** Returns the SSE stream URL for a session's canonical timeline. */
|
|
8144
|
+
sessionTimelineUrl(sessionId) {
|
|
8145
|
+
return `${this.baseUrl}/v1/sessions/${encodeURIComponent(sessionId)}/timeline`;
|
|
8146
|
+
}
|
|
8147
|
+
async get(path) {
|
|
8148
|
+
return this.request("GET", path, void 0);
|
|
8149
|
+
}
|
|
8150
|
+
async post(path, body) {
|
|
8151
|
+
return this.request("POST", path, body);
|
|
8152
|
+
}
|
|
8153
|
+
async patch(path, body) {
|
|
8154
|
+
return this.request("PATCH", path, body);
|
|
8155
|
+
}
|
|
8156
|
+
async request(method, path, body, isRetry = false) {
|
|
8157
|
+
const url = `${this.baseUrl}${path}`;
|
|
8158
|
+
const controller = new AbortController();
|
|
8159
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
8160
|
+
try {
|
|
8161
|
+
const response = await fetch(url, {
|
|
8162
|
+
method,
|
|
8163
|
+
headers: this.buildHeaders(),
|
|
8164
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
8165
|
+
signal: controller.signal
|
|
8166
|
+
});
|
|
8167
|
+
if (response.status === 401 && this.token && this.onTokenExpired && !isRetry) {
|
|
8168
|
+
const fresh = await this.onTokenExpired();
|
|
8169
|
+
if (fresh) {
|
|
8170
|
+
this.token = fresh;
|
|
8171
|
+
return this.request(method, path, body, true);
|
|
8172
|
+
}
|
|
8173
|
+
}
|
|
8174
|
+
if (!response.ok) {
|
|
8175
|
+
let errorMsg = `Flitro HTTP ${response.status}`;
|
|
8176
|
+
try {
|
|
8177
|
+
const errBody = await response.json();
|
|
8178
|
+
if (errBody.error) errorMsg = `${errorMsg}: ${errBody.error}`;
|
|
8179
|
+
} catch {
|
|
8180
|
+
}
|
|
8181
|
+
throw new Error(errorMsg);
|
|
8182
|
+
}
|
|
8183
|
+
return response.json();
|
|
8184
|
+
} finally {
|
|
8185
|
+
clearTimeout(timer);
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
};
|
|
8189
|
+
var FlitroFetchSseTimelineStream = class {
|
|
8190
|
+
listeners = /* @__PURE__ */ new Set();
|
|
8191
|
+
abortController = null;
|
|
8192
|
+
connected = false;
|
|
8193
|
+
disposed = false;
|
|
8194
|
+
afterSeq;
|
|
8195
|
+
reconnectAttempts = 0;
|
|
8196
|
+
tokenOverride = "";
|
|
8197
|
+
getBearerToken;
|
|
8198
|
+
onTokenExpired;
|
|
8199
|
+
options;
|
|
8200
|
+
constructor(options) {
|
|
8201
|
+
this.afterSeq = options.initialAfterSeq ?? 0;
|
|
8202
|
+
this.getBearerToken = options.getBearerToken;
|
|
8203
|
+
this.onTokenExpired = options.onTokenExpired;
|
|
8204
|
+
this.options = {
|
|
8205
|
+
url: options.url,
|
|
8206
|
+
apiKey: options.apiKey ?? "",
|
|
8207
|
+
tenantId: options.tenantId ?? "",
|
|
8208
|
+
reconnectDelayMs: options.reconnectDelayMs ?? 1500,
|
|
8209
|
+
maxReconnectAttempts: options.maxReconnectAttempts ?? 20,
|
|
8210
|
+
initialAfterSeq: this.afterSeq,
|
|
8211
|
+
now: options.now ?? (() => Date.now())
|
|
8212
|
+
};
|
|
8213
|
+
}
|
|
8214
|
+
connect(onEvent, onError, onClose) {
|
|
8215
|
+
this.disposed = false;
|
|
8216
|
+
this.listeners.add({ onEvent, onError, onClose });
|
|
8217
|
+
if (!this.connected) {
|
|
8218
|
+
this.connected = true;
|
|
8219
|
+
this.reconnectAttempts = 0;
|
|
8220
|
+
this.startFetch();
|
|
8221
|
+
}
|
|
8222
|
+
}
|
|
8223
|
+
disconnect() {
|
|
8224
|
+
this.disposed = true;
|
|
8225
|
+
this.connected = false;
|
|
8226
|
+
this.abortController?.abort();
|
|
8227
|
+
for (const listener of this.listeners) {
|
|
8228
|
+
listener.onClose?.();
|
|
8229
|
+
}
|
|
8230
|
+
this.listeners.clear();
|
|
8231
|
+
}
|
|
8232
|
+
isConnected() {
|
|
8233
|
+
return this.connected && !this.disposed;
|
|
8234
|
+
}
|
|
8235
|
+
buildUrl() {
|
|
8236
|
+
let url = this.options.url;
|
|
8237
|
+
if (this.afterSeq > 0) {
|
|
8238
|
+
url += (url.includes("?") ? "&" : "?") + `after_seq=${this.afterSeq}`;
|
|
8239
|
+
}
|
|
8240
|
+
return url;
|
|
8241
|
+
}
|
|
8242
|
+
buildHeaders() {
|
|
8243
|
+
const h = { Accept: "text/event-stream" };
|
|
8244
|
+
const bearer = this.tokenOverride || this.getBearerToken?.() || this.options.apiKey;
|
|
8245
|
+
if (bearer) h["Authorization"] = `Bearer ${bearer}`;
|
|
8246
|
+
if (this.options.tenantId) h["X-Tenant-ID"] = this.options.tenantId;
|
|
8247
|
+
return h;
|
|
8248
|
+
}
|
|
8249
|
+
async startFetch() {
|
|
8250
|
+
if (this.disposed) return;
|
|
8251
|
+
this.abortController = new AbortController();
|
|
8252
|
+
try {
|
|
8253
|
+
const response = await fetch(this.buildUrl(), {
|
|
8254
|
+
headers: this.buildHeaders(),
|
|
8255
|
+
signal: this.abortController.signal
|
|
8256
|
+
});
|
|
8257
|
+
if (response.status === 401 && this.onTokenExpired) {
|
|
8258
|
+
const fresh = await this.onTokenExpired();
|
|
8259
|
+
if (fresh) this.tokenOverride = fresh;
|
|
8260
|
+
}
|
|
8261
|
+
if (!response.ok || !response.body) {
|
|
8262
|
+
throw new Error(`Flitro SSE: HTTP ${response.status}`);
|
|
8263
|
+
}
|
|
8264
|
+
this.reconnectAttempts = 0;
|
|
8265
|
+
const reader = response.body.getReader();
|
|
8266
|
+
const decoder = new TextDecoder();
|
|
8267
|
+
let buffer = "";
|
|
8268
|
+
while (true) {
|
|
8269
|
+
const { done, value } = await reader.read();
|
|
8270
|
+
if (done) break;
|
|
8271
|
+
buffer += decoder.decode(value, { stream: true });
|
|
8272
|
+
const envelopes = parseSseBuffer(buffer);
|
|
8273
|
+
buffer = envelopes.remainder;
|
|
8274
|
+
for (const envelope of envelopes.items) {
|
|
8275
|
+
if (envelope.seq > this.afterSeq) {
|
|
8276
|
+
this.afterSeq = envelope.seq;
|
|
8277
|
+
}
|
|
8278
|
+
for (const listener of this.listeners) {
|
|
8279
|
+
listener.onEvent(envelope);
|
|
8280
|
+
}
|
|
8281
|
+
}
|
|
8282
|
+
}
|
|
8283
|
+
if (!this.disposed) {
|
|
8284
|
+
this.connected = false;
|
|
8285
|
+
this.scheduleReconnect();
|
|
8286
|
+
}
|
|
8287
|
+
} catch (err) {
|
|
8288
|
+
if (this.disposed) return;
|
|
8289
|
+
if (err instanceof Error && err.name === "AbortError") return;
|
|
8290
|
+
this.connected = false;
|
|
8291
|
+
this.scheduleReconnect();
|
|
8292
|
+
}
|
|
8293
|
+
}
|
|
8294
|
+
scheduleReconnect() {
|
|
8295
|
+
if (this.disposed) return;
|
|
8296
|
+
if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {
|
|
8297
|
+
this.emitError(new Error(`Flitro SSE: max reconnect attempts reached`));
|
|
8298
|
+
return;
|
|
8299
|
+
}
|
|
8300
|
+
this.reconnectAttempts++;
|
|
8301
|
+
const delay = Math.min(this.options.reconnectDelayMs * this.reconnectAttempts, 3e4);
|
|
8302
|
+
setTimeout(() => {
|
|
8303
|
+
this.connected = true;
|
|
8304
|
+
this.startFetch();
|
|
8305
|
+
}, delay);
|
|
8306
|
+
}
|
|
8307
|
+
emitError(err) {
|
|
8308
|
+
for (const listener of this.listeners) listener.onError?.(err);
|
|
8309
|
+
}
|
|
8310
|
+
};
|
|
8311
|
+
function parseSseBuffer(buffer) {
|
|
8312
|
+
const items = [];
|
|
8313
|
+
const blocks = buffer.split("\n\n");
|
|
8314
|
+
const remainder = blocks.pop() ?? "";
|
|
8315
|
+
for (const block of blocks) {
|
|
8316
|
+
let eventType = "";
|
|
8317
|
+
let data = "";
|
|
8318
|
+
for (const line of block.split("\n")) {
|
|
8319
|
+
if (line.startsWith("event: ")) {
|
|
8320
|
+
eventType = line.slice(7).trim();
|
|
8321
|
+
} else if (line.startsWith("data: ")) {
|
|
8322
|
+
data = line.slice(6).trim();
|
|
8323
|
+
}
|
|
8324
|
+
}
|
|
8325
|
+
if (eventType === "timeline" && data) {
|
|
8326
|
+
try {
|
|
8327
|
+
items.push(JSON.parse(data));
|
|
8328
|
+
} catch {
|
|
8329
|
+
}
|
|
8330
|
+
}
|
|
8331
|
+
}
|
|
8332
|
+
return { items, remainder };
|
|
8333
|
+
}
|
|
8334
|
+
function createFlitroTimelineStream(options) {
|
|
8335
|
+
return new FlitroFetchSseTimelineStream(options);
|
|
8336
|
+
}
|
|
8337
|
+
|
|
8338
|
+
// ../packages/provider-flitro/dist/index.js
|
|
8339
|
+
function mapPermissionModeToApprovalPolicy(mode) {
|
|
8340
|
+
if (mode === "allow-all") return "auto";
|
|
8341
|
+
if (mode === "safe") return "never";
|
|
8342
|
+
if (mode === "ask") return "on-request";
|
|
8343
|
+
return void 0;
|
|
8344
|
+
}
|
|
8345
|
+
function createFlitroDriver(options) {
|
|
8346
|
+
let activeRunId;
|
|
8347
|
+
return {
|
|
8348
|
+
async sendMessage(input, _sequencer) {
|
|
8349
|
+
const run = await options.client.sendMessage(
|
|
8350
|
+
options.sessionId,
|
|
8351
|
+
input.message,
|
|
8352
|
+
{
|
|
8353
|
+
model: input.options?.model ?? options.model,
|
|
8354
|
+
skillNames: options.skillNames,
|
|
8355
|
+
mcpServerNames: options.mcpServerNames,
|
|
8356
|
+
// Per-message permission choice (from the chat panel selector) wins
|
|
8357
|
+
// over the runtime's creation-time default.
|
|
8358
|
+
approvalPolicy: mapPermissionModeToApprovalPolicy(input.options?.permissionMode) ?? options.approvalPolicy
|
|
8359
|
+
}
|
|
8360
|
+
);
|
|
8361
|
+
activeRunId = run.run_id;
|
|
8362
|
+
},
|
|
8363
|
+
async abort(reason) {
|
|
8364
|
+
if (activeRunId) {
|
|
8365
|
+
await options.client.cancelRun(activeRunId).catch(() => {
|
|
8366
|
+
});
|
|
8367
|
+
activeRunId = void 0;
|
|
8368
|
+
}
|
|
8369
|
+
},
|
|
8370
|
+
async respondToPermission(requestId, allowed, remember) {
|
|
8371
|
+
await options.client.respondToPermission(options.sessionId, requestId, allowed, {
|
|
8372
|
+
remember
|
|
8373
|
+
});
|
|
8374
|
+
},
|
|
8375
|
+
async resumeTool(runId, resumeData) {
|
|
8376
|
+
await options.client.resumeTool(runId, resumeData);
|
|
8377
|
+
},
|
|
8378
|
+
async dispose() {
|
|
8379
|
+
if (activeRunId) {
|
|
8380
|
+
await options.client.cancelRun(activeRunId).catch(() => {
|
|
8381
|
+
});
|
|
8382
|
+
activeRunId = void 0;
|
|
8383
|
+
}
|
|
8384
|
+
}
|
|
8385
|
+
};
|
|
8386
|
+
}
|
|
8387
|
+
function createFlitroRuntimeCapabilityReport(options) {
|
|
8388
|
+
const appServerAvailable = options.candidates.some((c) => c.kind === "app-server" && c.available);
|
|
8389
|
+
return createRuntimeCapabilityReport({
|
|
8390
|
+
provider: "flitro",
|
|
8391
|
+
candidates: options.candidates,
|
|
8392
|
+
preferredRuntime: "app-server",
|
|
8393
|
+
allowFallback: options.allowFallback,
|
|
8394
|
+
auth: options.auth,
|
|
8395
|
+
extensionCapabilities: {
|
|
8396
|
+
policy: {
|
|
8397
|
+
supported: true,
|
|
8398
|
+
degraded: !appServerAvailable || void 0,
|
|
8399
|
+
modes: ["safe", "ask", "allow-all"],
|
|
8400
|
+
approvals: appServerAvailable,
|
|
8401
|
+
toolPolicy: appServerAvailable,
|
|
8402
|
+
reason: appServerAvailable ? void 0 : "Flitro server is unavailable"
|
|
8403
|
+
},
|
|
8404
|
+
sources: {
|
|
8405
|
+
supported: appServerAvailable,
|
|
8406
|
+
registry: appServerAvailable,
|
|
8407
|
+
mcpTools: appServerAvailable,
|
|
8408
|
+
credentialGateway: false,
|
|
8409
|
+
reason: appServerAvailable ? void 0 : "Source tools require a running Flitro server"
|
|
8410
|
+
},
|
|
8411
|
+
skills: {
|
|
8412
|
+
supported: appServerAvailable,
|
|
8413
|
+
registry: appServerAvailable,
|
|
8414
|
+
activationPlan: appServerAvailable,
|
|
8415
|
+
scopedPolicy: appServerAvailable,
|
|
8416
|
+
reason: appServerAvailable ? void 0 : "Skill activation requires a running Flitro server"
|
|
8417
|
+
},
|
|
8418
|
+
automations: {
|
|
8419
|
+
supported: appServerAvailable,
|
|
8420
|
+
degraded: !appServerAvailable || void 0,
|
|
8421
|
+
eventBus: appServerAvailable,
|
|
8422
|
+
schedulerHost: appServerAvailable,
|
|
8423
|
+
promptAction: appServerAvailable,
|
|
8424
|
+
webhookAction: false,
|
|
8425
|
+
reason: appServerAvailable ? void 0 : "Automations require a running Flitro server"
|
|
8426
|
+
},
|
|
8427
|
+
hostTools: {
|
|
8428
|
+
supported: appServerAvailable,
|
|
8429
|
+
sessionTools: false,
|
|
8430
|
+
workflowTransitions: false,
|
|
8431
|
+
browserActions: false,
|
|
8432
|
+
metadataWrites: appServerAvailable
|
|
8433
|
+
}
|
|
8434
|
+
}
|
|
8435
|
+
});
|
|
8436
|
+
}
|
|
8437
|
+
function createFlitroProviderRuntime(options) {
|
|
8438
|
+
const report = createFlitroRuntimeCapabilityReport(options);
|
|
8439
|
+
const extensions = createRuntimeExtensionContext(options.extensions);
|
|
8440
|
+
const client = new FlitroHttpClient(options.server);
|
|
8441
|
+
let resolvedSessionId = options.sessionId ?? "";
|
|
8442
|
+
let epoch = options.epoch ?? (resolvedSessionId ? `flitro-${resolvedSessionId}` : "flitro-pending");
|
|
8443
|
+
const now = options.now ?? (() => Date.now());
|
|
8444
|
+
const timeline = [];
|
|
8445
|
+
const seenTimelineKeys = /* @__PURE__ */ new Set();
|
|
8446
|
+
const stream = new PushTimelineStream();
|
|
8447
|
+
let state = initialRuntimeState;
|
|
8448
|
+
let runtimeDriver = options.driver;
|
|
8449
|
+
let sseStream;
|
|
8450
|
+
const pendingMessages = [];
|
|
8451
|
+
function dispatch(action) {
|
|
8452
|
+
state = reduceRuntimeState(state, action);
|
|
8453
|
+
}
|
|
8454
|
+
function syncStateFromEnvelope(envelope) {
|
|
8455
|
+
const item = envelope.item;
|
|
8456
|
+
if (item.type === "permission_requested") {
|
|
8457
|
+
dispatch({ type: "permission_request", requestId: item.request.requestId });
|
|
8458
|
+
} else if (item.type === "permission_resolved") {
|
|
8459
|
+
dispatch({ type: "permission_response" });
|
|
8460
|
+
} else if (item.type === "turn_completed") {
|
|
8461
|
+
dispatch({ type: "turn_completed" });
|
|
8462
|
+
dispatch({ type: "complete" });
|
|
8463
|
+
void sendNextPendingMessage();
|
|
8464
|
+
} else if (item.type === "turn_failed") {
|
|
8465
|
+
const err = item.error;
|
|
8466
|
+
dispatch({ type: "error", error: err?.message ?? "turn failed" });
|
|
8467
|
+
} else if (item.type === "tool_suspended") {
|
|
8468
|
+
dispatch({ type: "permission_request", requestId: `tool-suspend:${item.callId}` });
|
|
8469
|
+
} else if (item.type === "tool_resumed") {
|
|
8470
|
+
dispatch({ type: "permission_response" });
|
|
8471
|
+
} else if (item.type === "session_status") {
|
|
8472
|
+
if (item.status === "running") {
|
|
8473
|
+
dispatch({ type: "starting" });
|
|
8474
|
+
} else if (item.status === "ended") {
|
|
8475
|
+
dispatch({ type: "abort" });
|
|
8476
|
+
}
|
|
8477
|
+
}
|
|
8478
|
+
}
|
|
8479
|
+
function appendEnvelope(envelope) {
|
|
8480
|
+
if (envelope.seq > 0) {
|
|
8481
|
+
const key = `${envelope.epoch || envelope.sessionId || "unknown"}:${envelope.seq}`;
|
|
8482
|
+
if (seenTimelineKeys.has(key)) return;
|
|
8483
|
+
seenTimelineKeys.add(key);
|
|
8484
|
+
}
|
|
8485
|
+
syncStateFromEnvelope(envelope);
|
|
8486
|
+
timeline.push(envelope);
|
|
8487
|
+
stream.emit(envelope);
|
|
8488
|
+
}
|
|
8489
|
+
function appendFailure(message) {
|
|
8490
|
+
const item = { type: "turn_failed", turnId: "provider-runtime", error: { message } };
|
|
8491
|
+
const envelope = {
|
|
8492
|
+
sessionId: resolvedSessionId,
|
|
8493
|
+
provider: "flitro",
|
|
8494
|
+
seq: timeline.length + 1,
|
|
8495
|
+
epoch,
|
|
8496
|
+
timestamp: now(),
|
|
8497
|
+
item
|
|
8498
|
+
};
|
|
8499
|
+
appendEnvelope(envelope);
|
|
8500
|
+
}
|
|
8501
|
+
function getDriver() {
|
|
8502
|
+
if (runtimeDriver) return runtimeDriver;
|
|
8503
|
+
runtimeDriver = createFlitroDriver({
|
|
8504
|
+
client,
|
|
8505
|
+
sessionId: resolvedSessionId,
|
|
8506
|
+
model: options.model,
|
|
8507
|
+
skillNames: options.skillNames,
|
|
8508
|
+
mcpServerNames: options.mcpServerNames,
|
|
8509
|
+
approvalPolicy: options.approvalPolicy
|
|
8510
|
+
});
|
|
8511
|
+
return runtimeDriver;
|
|
8512
|
+
}
|
|
8513
|
+
async function sendToFlitro(message, sendOptions) {
|
|
8514
|
+
const driver = getDriver();
|
|
8515
|
+
try {
|
|
8516
|
+
await driver.sendMessage({ message, options: sendOptions }, {
|
|
8517
|
+
append: (item, rawRef) => {
|
|
8518
|
+
const envelope = {
|
|
8519
|
+
sessionId: resolvedSessionId,
|
|
8520
|
+
provider: "flitro",
|
|
8521
|
+
seq: timeline.length + 1,
|
|
8522
|
+
epoch,
|
|
8523
|
+
timestamp: now(),
|
|
8524
|
+
item,
|
|
8525
|
+
rawRef
|
|
8526
|
+
};
|
|
8527
|
+
appendEnvelope(envelope);
|
|
8528
|
+
return envelope;
|
|
8529
|
+
}
|
|
8530
|
+
});
|
|
8531
|
+
} catch (err) {
|
|
8532
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
8533
|
+
dispatch({ type: "error", error });
|
|
8534
|
+
appendFailure(error);
|
|
8535
|
+
throw err;
|
|
8536
|
+
}
|
|
8537
|
+
}
|
|
8538
|
+
async function sendNextPendingMessage() {
|
|
8539
|
+
const next = pendingMessages.shift();
|
|
8540
|
+
if (!next) return;
|
|
8541
|
+
try {
|
|
8542
|
+
await sendToFlitro(next.message, next.options);
|
|
8543
|
+
} catch {
|
|
8544
|
+
}
|
|
8545
|
+
}
|
|
8546
|
+
async function ensureSession() {
|
|
8547
|
+
if (resolvedSessionId) return;
|
|
8548
|
+
const session = await client.createSession({
|
|
8549
|
+
model: options.model,
|
|
8550
|
+
skillNames: options.skillNames,
|
|
8551
|
+
mcpServerNames: options.mcpServerNames
|
|
8552
|
+
});
|
|
8553
|
+
resolvedSessionId = session.session_id;
|
|
8554
|
+
if (!options.epoch) {
|
|
8555
|
+
epoch = `flitro-${resolvedSessionId}`;
|
|
8556
|
+
}
|
|
8557
|
+
connectSse();
|
|
8558
|
+
}
|
|
8559
|
+
function connectSse() {
|
|
8560
|
+
if (!resolvedSessionId || sseStream) return;
|
|
8561
|
+
sseStream = createFlitroTimelineStream({
|
|
8562
|
+
url: client.sessionTimelineUrl(resolvedSessionId),
|
|
8563
|
+
apiKey: options.server.apiKey,
|
|
8564
|
+
tenantId: options.server.tenantId,
|
|
8565
|
+
// Scoped embed tokens rotate; always read the client's current bearer
|
|
8566
|
+
// and propagate refreshed tokens back to it.
|
|
8567
|
+
getBearerToken: () => client.getBearerToken(),
|
|
8568
|
+
onTokenExpired: options.server.onTokenExpired ? async () => {
|
|
8569
|
+
const fresh = await options.server.onTokenExpired?.();
|
|
8570
|
+
if (fresh) client.setToken(fresh);
|
|
8571
|
+
return fresh;
|
|
8572
|
+
} : void 0
|
|
8573
|
+
});
|
|
8574
|
+
sseStream.connect(
|
|
8575
|
+
// The client package types `item` as unknown; the server emits the
|
|
8576
|
+
// canonical Weft envelope, so this is the narrowing point.
|
|
8577
|
+
(envelope) => appendEnvelope(envelope),
|
|
8578
|
+
(_err) => {
|
|
8579
|
+
}
|
|
8580
|
+
);
|
|
8581
|
+
}
|
|
8582
|
+
if (resolvedSessionId) {
|
|
8583
|
+
connectSse();
|
|
8584
|
+
}
|
|
8585
|
+
return {
|
|
8586
|
+
get sessionId() {
|
|
8587
|
+
return resolvedSessionId;
|
|
8588
|
+
},
|
|
8589
|
+
provider: "flitro",
|
|
8590
|
+
runtimeKind: report.selected ?? "app-server",
|
|
8591
|
+
events: stream,
|
|
8592
|
+
commands: {
|
|
8593
|
+
async sendMessage(message, sendOptions) {
|
|
8594
|
+
await ensureSession();
|
|
8595
|
+
const shouldQueue = state.status === "running" || state.status === "waiting_for_permission";
|
|
8596
|
+
dispatch({ type: "send_message", message });
|
|
8597
|
+
if (shouldQueue) {
|
|
8598
|
+
pendingMessages.push({ message, options: sendOptions });
|
|
8599
|
+
return;
|
|
8600
|
+
}
|
|
8601
|
+
await sendToFlitro(message, sendOptions);
|
|
8602
|
+
},
|
|
8603
|
+
async abort(reason) {
|
|
8604
|
+
dispatch({ type: "abort", reason });
|
|
8605
|
+
pendingMessages.length = 0;
|
|
8606
|
+
await runtimeDriver?.abort?.(reason);
|
|
8607
|
+
},
|
|
8608
|
+
async respondToPermission(requestId, allowed, remember) {
|
|
8609
|
+
await getDriver().respondToPermission?.(requestId, allowed, remember);
|
|
8610
|
+
dispatch({ type: "permission_response" });
|
|
8611
|
+
},
|
|
8612
|
+
async resumeTool(runId, resumeData) {
|
|
8613
|
+
await getDriver().resumeTool?.(runId, resumeData);
|
|
8614
|
+
},
|
|
8615
|
+
async dispose() {
|
|
8616
|
+
dispatch({ type: "dispose" });
|
|
8617
|
+
pendingMessages.length = 0;
|
|
8618
|
+
sseStream?.disconnect();
|
|
8619
|
+
sseStream = void 0;
|
|
8620
|
+
await runtimeDriver?.dispose?.();
|
|
8621
|
+
}
|
|
8622
|
+
},
|
|
8623
|
+
async preflight() {
|
|
8624
|
+
dispatch({ type: "preflight_start" });
|
|
8625
|
+
if (!report.selected) {
|
|
8626
|
+
dispatch({ type: "preflight_error", error: report.error ?? "No runtime selected" });
|
|
8627
|
+
} else {
|
|
8628
|
+
dispatch({ type: "preflight_ok" });
|
|
8629
|
+
}
|
|
8630
|
+
const capItem = { type: "runtime_capability_report", report };
|
|
8631
|
+
const capEnvelope = {
|
|
8632
|
+
sessionId: resolvedSessionId,
|
|
8633
|
+
provider: "flitro",
|
|
8634
|
+
seq: timeline.length + 1,
|
|
8635
|
+
epoch,
|
|
8636
|
+
timestamp: now(),
|
|
8637
|
+
item: capItem
|
|
8638
|
+
};
|
|
8639
|
+
appendEnvelope(capEnvelope);
|
|
8640
|
+
return report;
|
|
8641
|
+
},
|
|
8642
|
+
async fetchTimeline(request = {}) {
|
|
8643
|
+
if (request.cursor?.epoch === epoch || !request.cursor) {
|
|
8644
|
+
const localResult = fetchTimeline(timeline, request);
|
|
8645
|
+
if (localResult.items.length > 0) return localResult;
|
|
8646
|
+
}
|
|
8647
|
+
if (resolvedSessionId) {
|
|
8648
|
+
try {
|
|
8649
|
+
const afterSeq = request.cursor?.afterSeq ?? 0;
|
|
8650
|
+
const result = await client.fetchTimeline(resolvedSessionId, afterSeq, request.limit);
|
|
8651
|
+
return {
|
|
8652
|
+
items: result.items,
|
|
8653
|
+
nextCursor: createTimelineCursor({
|
|
8654
|
+
epoch: result.nextCursor.epoch,
|
|
8655
|
+
afterSeq: result.nextCursor.afterSeq
|
|
8656
|
+
}),
|
|
8657
|
+
hasGap: result.hasGap
|
|
8658
|
+
};
|
|
8659
|
+
} catch {
|
|
8660
|
+
}
|
|
8661
|
+
}
|
|
8662
|
+
return {
|
|
8663
|
+
items: [],
|
|
8664
|
+
nextCursor: createTimelineCursor({ epoch, afterSeq: 0 }),
|
|
8665
|
+
hasGap: false
|
|
8666
|
+
};
|
|
8667
|
+
},
|
|
8668
|
+
getState() {
|
|
8669
|
+
return state;
|
|
8670
|
+
}
|
|
8671
|
+
};
|
|
8672
|
+
}
|
|
8673
|
+
function createFlitroEmbedRuntime(options) {
|
|
8674
|
+
return createFlitroProviderRuntime({
|
|
8675
|
+
server: {
|
|
8676
|
+
baseUrl: options.baseUrl,
|
|
8677
|
+
token: options.token,
|
|
8678
|
+
onTokenExpired: options.onTokenExpired
|
|
8679
|
+
},
|
|
8680
|
+
sessionId: options.sessionId,
|
|
8681
|
+
epoch: options.epoch,
|
|
8682
|
+
now: options.now,
|
|
8683
|
+
extensions: options.extensions,
|
|
8684
|
+
candidates: [{ kind: "app-server", available: true }],
|
|
8685
|
+
auth: { mode: "provider-owned", configured: true, source: "flitro-embed" }
|
|
8686
|
+
});
|
|
8687
|
+
}
|
|
8688
|
+
var PushTimelineStream = class {
|
|
8689
|
+
listeners = /* @__PURE__ */ new Set();
|
|
8690
|
+
connect(onEvent, onError, onClose) {
|
|
8691
|
+
this.listeners.add({ onEvent, onError, onClose });
|
|
8692
|
+
}
|
|
8693
|
+
disconnect() {
|
|
8694
|
+
for (const l of this.listeners) l.onClose?.();
|
|
8695
|
+
this.listeners.clear();
|
|
8696
|
+
}
|
|
8697
|
+
isConnected() {
|
|
8698
|
+
return this.listeners.size > 0;
|
|
8699
|
+
}
|
|
8700
|
+
emit(event) {
|
|
8701
|
+
for (const l of this.listeners) l.onEvent(event);
|
|
8702
|
+
}
|
|
8703
|
+
};
|
|
8704
|
+
|
|
8705
|
+
// ../packages/react/src/use-agent-session.ts
|
|
8706
|
+
function useAgentSession(options) {
|
|
8707
|
+
const onTokenExpiredRef = useRef9(options.onTokenExpired);
|
|
8708
|
+
onTokenExpiredRef.current = options.onTokenExpired;
|
|
8709
|
+
const tokenRef = useRef9(options.token);
|
|
8710
|
+
tokenRef.current = options.token;
|
|
8711
|
+
const runtime = useMemo9(() => {
|
|
8712
|
+
return createDeferredAgentRuntime({
|
|
8713
|
+
provider: "flitro",
|
|
8714
|
+
runtimeKind: "app-server",
|
|
8715
|
+
sessionId: options.sessionId,
|
|
8716
|
+
createRuntime: () => createFlitroEmbedRuntime({
|
|
8717
|
+
baseUrl: options.server,
|
|
8718
|
+
token: tokenRef.current,
|
|
8719
|
+
sessionId: options.sessionId,
|
|
8720
|
+
onTokenExpired: () => onTokenExpiredRef.current?.()
|
|
8721
|
+
})
|
|
8722
|
+
});
|
|
8723
|
+
}, [options.server, options.sessionId]);
|
|
8724
|
+
useEffect10(() => {
|
|
8725
|
+
return () => {
|
|
8726
|
+
void runtime.disposeIfCreated();
|
|
8727
|
+
};
|
|
8728
|
+
}, [runtime]);
|
|
8729
|
+
return { runtime, sessionId: options.sessionId, server: options.server };
|
|
8730
|
+
}
|
|
8731
|
+
function createDeferredAgentRuntime(options) {
|
|
8732
|
+
let runtime = null;
|
|
8733
|
+
let disposed = false;
|
|
8734
|
+
const getRuntime = () => {
|
|
8735
|
+
if (disposed) {
|
|
8736
|
+
throw new Error("Agent runtime has been disposed");
|
|
8737
|
+
}
|
|
8738
|
+
runtime ??= options.createRuntime();
|
|
8739
|
+
return runtime;
|
|
8740
|
+
};
|
|
8741
|
+
return {
|
|
8742
|
+
get sessionId() {
|
|
8743
|
+
return runtime?.sessionId ?? options.sessionId;
|
|
8744
|
+
},
|
|
8745
|
+
get provider() {
|
|
8746
|
+
return runtime?.provider ?? options.provider;
|
|
8747
|
+
},
|
|
8748
|
+
get runtimeKind() {
|
|
8749
|
+
return runtime?.runtimeKind ?? options.runtimeKind;
|
|
8750
|
+
},
|
|
8751
|
+
events: {
|
|
8752
|
+
connect(onEvent, onError, onClose) {
|
|
8753
|
+
getRuntime().events.connect(onEvent, onError, onClose);
|
|
8754
|
+
},
|
|
8755
|
+
disconnect() {
|
|
8756
|
+
runtime?.events.disconnect();
|
|
8757
|
+
},
|
|
8758
|
+
isConnected() {
|
|
8759
|
+
return runtime?.events.isConnected() ?? false;
|
|
8760
|
+
}
|
|
8761
|
+
},
|
|
8762
|
+
commands: {
|
|
8763
|
+
sendMessage(message, sendOptions) {
|
|
8764
|
+
return getRuntime().commands.sendMessage(message, sendOptions);
|
|
8765
|
+
},
|
|
8766
|
+
abort(reason) {
|
|
8767
|
+
return getRuntime().commands.abort(reason);
|
|
8768
|
+
},
|
|
8769
|
+
respondToPermission(requestId, allowed, remember) {
|
|
8770
|
+
return getRuntime().commands.respondToPermission(requestId, allowed, remember);
|
|
8771
|
+
},
|
|
8772
|
+
async resumeTool(runId, resumeData) {
|
|
8773
|
+
const commands = getRuntime().commands;
|
|
8774
|
+
if (!commands.resumeTool) {
|
|
8775
|
+
throw new Error(`resumeTool is not supported by the ${options.provider} runtime`);
|
|
8776
|
+
}
|
|
8777
|
+
await commands.resumeTool(runId, resumeData);
|
|
8778
|
+
},
|
|
8779
|
+
dispose() {
|
|
8780
|
+
disposed = true;
|
|
8781
|
+
const current = runtime;
|
|
8782
|
+
runtime = null;
|
|
8783
|
+
return current?.commands.dispose() ?? Promise.resolve();
|
|
8784
|
+
}
|
|
8785
|
+
},
|
|
8786
|
+
preflight() {
|
|
8787
|
+
return getRuntime().preflight();
|
|
8788
|
+
},
|
|
8789
|
+
fetchTimeline(request) {
|
|
8790
|
+
return getRuntime().fetchTimeline(request);
|
|
8791
|
+
},
|
|
8792
|
+
getState() {
|
|
8793
|
+
return runtime?.getState() ?? {
|
|
8794
|
+
status: initialRuntimeState.status,
|
|
8795
|
+
acceptedMessages: [],
|
|
8796
|
+
queuedMessages: []
|
|
8797
|
+
};
|
|
8798
|
+
},
|
|
8799
|
+
async disposeIfCreated() {
|
|
8800
|
+
if (!runtime) return;
|
|
8801
|
+
const current = runtime;
|
|
8802
|
+
runtime = null;
|
|
8803
|
+
await current.commands.dispose();
|
|
8804
|
+
}
|
|
8805
|
+
};
|
|
8806
|
+
}
|
|
7828
8807
|
export {
|
|
7829
8808
|
ActivityDetailsPanel,
|
|
7830
8809
|
ActivityInspector,
|