@okrlinkhub/agent-factory 0.2.9 → 0.2.11

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.
Files changed (71) hide show
  1. package/package.json +1 -1
  2. package/src/component/lib.test.ts +100 -1
  3. package/src/component/pushing.ts +64 -4
  4. package/dist/client/_generated/_ignore.d.ts +0 -1
  5. package/dist/client/_generated/_ignore.d.ts.map +0 -1
  6. package/dist/client/_generated/_ignore.js +0 -3
  7. package/dist/client/_generated/_ignore.js.map +0 -1
  8. package/dist/client/bridge.d.ts +0 -65
  9. package/dist/client/bridge.d.ts.map +0 -1
  10. package/dist/client/bridge.js +0 -192
  11. package/dist/client/bridge.js.map +0 -1
  12. package/dist/client/index.d.ts +0 -516
  13. package/dist/client/index.d.ts.map +0 -1
  14. package/dist/client/index.js +0 -795
  15. package/dist/client/index.js.map +0 -1
  16. package/dist/component/_generated/api.d.ts +0 -46
  17. package/dist/component/_generated/api.d.ts.map +0 -1
  18. package/dist/component/_generated/api.js +0 -31
  19. package/dist/component/_generated/api.js.map +0 -1
  20. package/dist/component/_generated/component.d.ts +0 -1396
  21. package/dist/component/_generated/component.d.ts.map +0 -1
  22. package/dist/component/_generated/component.js +0 -11
  23. package/dist/component/_generated/component.js.map +0 -1
  24. package/dist/component/_generated/dataModel.d.ts +0 -46
  25. package/dist/component/_generated/dataModel.d.ts.map +0 -1
  26. package/dist/component/_generated/dataModel.js +0 -11
  27. package/dist/component/_generated/dataModel.js.map +0 -1
  28. package/dist/component/_generated/server.d.ts +0 -121
  29. package/dist/component/_generated/server.d.ts.map +0 -1
  30. package/dist/component/_generated/server.js +0 -78
  31. package/dist/component/_generated/server.js.map +0 -1
  32. package/dist/component/config.d.ts +0 -254
  33. package/dist/component/config.d.ts.map +0 -1
  34. package/dist/component/config.js +0 -152
  35. package/dist/component/config.js.map +0 -1
  36. package/dist/component/convex.config.d.ts +0 -3
  37. package/dist/component/convex.config.d.ts.map +0 -1
  38. package/dist/component/convex.config.js +0 -3
  39. package/dist/component/convex.config.js.map +0 -1
  40. package/dist/component/identity.d.ts +0 -111
  41. package/dist/component/identity.d.ts.map +0 -1
  42. package/dist/component/identity.js +0 -455
  43. package/dist/component/identity.js.map +0 -1
  44. package/dist/component/lib.d.ts +0 -6
  45. package/dist/component/lib.d.ts.map +0 -1
  46. package/dist/component/lib.js +0 -6
  47. package/dist/component/lib.js.map +0 -1
  48. package/dist/component/providers/fly.d.ts +0 -51
  49. package/dist/component/providers/fly.d.ts.map +0 -1
  50. package/dist/component/providers/fly.js +0 -234
  51. package/dist/component/providers/fly.js.map +0 -1
  52. package/dist/component/pushing.d.ts +0 -256
  53. package/dist/component/pushing.d.ts.map +0 -1
  54. package/dist/component/pushing.js +0 -962
  55. package/dist/component/pushing.js.map +0 -1
  56. package/dist/component/queue.d.ts +0 -361
  57. package/dist/component/queue.d.ts.map +0 -1
  58. package/dist/component/queue.js +0 -1407
  59. package/dist/component/queue.js.map +0 -1
  60. package/dist/component/scheduler.d.ts +0 -116
  61. package/dist/component/scheduler.d.ts.map +0 -1
  62. package/dist/component/scheduler.js +0 -410
  63. package/dist/component/scheduler.js.map +0 -1
  64. package/dist/component/schema.d.ts +0 -648
  65. package/dist/component/schema.d.ts.map +0 -1
  66. package/dist/component/schema.js +0 -295
  67. package/dist/component/schema.js.map +0 -1
  68. package/dist/react/index.d.ts +0 -2
  69. package/dist/react/index.d.ts.map +0 -1
  70. package/dist/react/index.js +0 -6
  71. package/dist/react/index.js.map +0 -1
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/okrlinkhub/agent-factory/issues"
11
11
  },
12
- "version": "0.2.9",
12
+ "version": "0.2.11",
13
13
  "license": "Apache-2.0",
14
14
  "keywords": [
15
15
  "convex",
@@ -457,7 +457,7 @@ describe("component lib", () => {
457
457
  expect(reconcile.terminated).toBe(0);
458
458
  });
459
459
 
460
- test("push jobs should dispatch scheduled messages and log runs", async () => {
460
+ test("push jobs should dispatch scheduled messages with fallback user conversation id", async () => {
461
461
  const t = initConvexTest();
462
462
  await t.mutation(api.queue.upsertAgentProfile, {
463
463
  agentKey: "push-agent",
@@ -499,6 +499,10 @@ describe("component lib", () => {
499
499
 
500
500
  const queueStats = await t.query(api.lib.queueStats, {});
501
501
  expect(queueStats.queuedReady).toBe(1);
502
+ const claim = await t.mutation(api.lib.claim, { workerId: "worker-push-fallback-1" });
503
+ expect(claim?.conversationId).toBe("user:user-push-1");
504
+ expect(claim?.payload.provider).toBe("system_push");
505
+ expect(claim?.payload.providerUserId).toBe("user-push-1");
502
506
 
503
507
  const jobDispatches = await t.query((api.lib as any).listPushDispatchesByJob, {
504
508
  jobId,
@@ -508,6 +512,101 @@ describe("component lib", () => {
508
512
  expect(jobDispatches[0].status).toBe("enqueued");
509
513
  });
510
514
 
515
+ test("triggerPushJobNow should reuse telegram chat conversation id", async () => {
516
+ const t = initConvexTest();
517
+ await t.mutation(api.queue.upsertAgentProfile, {
518
+ agentKey: "push-telegram-manual-agent",
519
+ version: "1.0.0",
520
+ soulMd: "# Soul",
521
+ clientMd: "# Client",
522
+ skills: [],
523
+ secretsRef: [],
524
+ enabled: true,
525
+ });
526
+ await t.mutation(api.lib.bindUserAgent, {
527
+ consumerUserId: "user-push-telegram-manual",
528
+ agentKey: "push-telegram-manual-agent",
529
+ source: "telegram_pairing",
530
+ telegramUserId: "tg-user-manual-1",
531
+ telegramChatId: "8246761447",
532
+ });
533
+
534
+ const nowMs = Date.UTC(2026, 0, 1, 8, 0, 0);
535
+ const jobId = await t.mutation((api.lib as any).createPushJobCustom, {
536
+ companyId: "co-tg-manual",
537
+ consumerUserId: "user-push-telegram-manual",
538
+ title: "Manual push",
539
+ text: "Messaggio manuale",
540
+ periodicity: "manual",
541
+ timezone: "UTC",
542
+ schedule: {
543
+ kind: "manual",
544
+ },
545
+ nowMs,
546
+ });
547
+
548
+ await t.mutation((api.lib as any).triggerPushJobNow, {
549
+ jobId,
550
+ nowMs,
551
+ });
552
+
553
+ const claim = await t.mutation(api.lib.claim, { workerId: "worker-push-telegram-manual-1" });
554
+ expect(claim?.conversationId).toBe("telegram:8246761447");
555
+ expect(claim?.payload.provider).toBe("telegram");
556
+ expect(claim?.payload.providerUserId).toBe("tg-user-manual-1");
557
+ expect(claim?.payload.metadata?.telegramChatId).toBe("8246761447");
558
+ expect(claim?.payload.metadata?.telegramUserId).toBe("tg-user-manual-1");
559
+ });
560
+
561
+ test("dispatchDuePushJobs should reuse telegram chat conversation id when available", async () => {
562
+ const t = initConvexTest();
563
+ await t.mutation(api.queue.upsertAgentProfile, {
564
+ agentKey: "push-telegram-scheduled-agent",
565
+ version: "1.0.0",
566
+ soulMd: "# Soul",
567
+ clientMd: "# Client",
568
+ skills: [],
569
+ secretsRef: [],
570
+ enabled: true,
571
+ });
572
+ await t.mutation(api.lib.bindUserAgent, {
573
+ consumerUserId: "user-push-telegram-scheduled",
574
+ agentKey: "push-telegram-scheduled-agent",
575
+ source: "telegram_pairing",
576
+ telegramUserId: "tg-user-scheduled-1",
577
+ telegramChatId: "9988776655",
578
+ });
579
+
580
+ const baseMs = Date.UTC(2026, 0, 1, 7, 59, 0);
581
+ await t.mutation((api.lib as any).createPushJobCustom, {
582
+ companyId: "co-tg-scheduled",
583
+ consumerUserId: "user-push-telegram-scheduled",
584
+ title: "Daily telegram check",
585
+ text: "Ping telegram",
586
+ periodicity: "daily",
587
+ timezone: "UTC",
588
+ schedule: {
589
+ kind: "daily",
590
+ time: "08:00",
591
+ },
592
+ nowMs: baseMs,
593
+ });
594
+
595
+ const dispatch = await t.mutation((api.lib as any).dispatchDuePushJobs, {
596
+ nowMs: baseMs + 6 * 60_000,
597
+ limit: 50,
598
+ });
599
+ expect(dispatch.enqueued).toBe(1);
600
+ expect(dispatch.failed).toBe(0);
601
+
602
+ const claim = await t.mutation(api.lib.claim, { workerId: "worker-push-telegram-scheduled-1" });
603
+ expect(claim?.conversationId).toBe("telegram:9988776655");
604
+ expect(claim?.payload.provider).toBe("telegram");
605
+ expect(claim?.payload.providerUserId).toBe("tg-user-scheduled-1");
606
+ expect(claim?.payload.metadata?.telegramChatId).toBe("9988776655");
607
+ expect(claim?.payload.metadata?.telegramUserId).toBe("tg-user-scheduled-1");
608
+ });
609
+
511
610
  test("admin broadcast should enqueue to all active company agents", async () => {
512
611
  const t = initConvexTest();
513
612
  await t.mutation(api.queue.upsertAgentProfile, {
@@ -477,9 +477,13 @@ export const triggerPushJobNow = mutation({
477
477
  if (!agentKey) {
478
478
  throw new Error("No active agent binding for user");
479
479
  }
480
+ const conversationTarget = await resolveConversationTargetForUser(ctx, job.consumerUserId);
480
481
  const runKey = `manual:${job._id}:${nowMs}`;
482
+ const targetProviderUserId = conversationTarget.source === "telegram_chat"
483
+ ? (conversationTarget.telegramUserId ?? conversationTarget.telegramChatId ?? job.consumerUserId)
484
+ : job.consumerUserId;
481
485
  const messageId = await enqueuePushMessage(ctx, {
482
- conversationId: `user:${job.consumerUserId}`,
486
+ conversationId: conversationTarget.conversationId,
483
487
  agentKey,
484
488
  consumerUserId: job.consumerUserId,
485
489
  text: job.text,
@@ -487,8 +491,17 @@ export const triggerPushJobNow = mutation({
487
491
  pushJobId: String(job._id),
488
492
  runKey,
489
493
  pushMode: "manual",
494
+ conversationTargetSource: conversationTarget.source,
495
+ ...(conversationTarget.telegramChatId
496
+ ? { telegramChatId: conversationTarget.telegramChatId }
497
+ : {}),
498
+ ...(conversationTarget.telegramUserId
499
+ ? { telegramUserId: conversationTarget.telegramUserId }
500
+ : {}),
490
501
  },
491
502
  scheduledFor: nowMs,
503
+ provider: conversationTarget.source === "telegram_chat" ? "telegram" : "system_push",
504
+ providerUserId: targetProviderUserId,
492
505
  providerConfig: args.providerConfig,
493
506
  });
494
507
  await ctx.db.insert("messagePushDispatches", {
@@ -578,9 +591,13 @@ export const dispatchDuePushJobs = mutation({
578
591
  failed += 1;
579
592
  continue;
580
593
  }
594
+ const conversationTarget = await resolveConversationTargetForUser(ctx, job.consumerUserId);
581
595
  try {
596
+ const targetProviderUserId = conversationTarget.source === "telegram_chat"
597
+ ? (conversationTarget.telegramUserId ?? conversationTarget.telegramChatId ?? job.consumerUserId)
598
+ : job.consumerUserId;
582
599
  const messageId = await enqueuePushMessage(ctx, {
583
- conversationId: `user:${job.consumerUserId}`,
600
+ conversationId: conversationTarget.conversationId,
584
601
  agentKey,
585
602
  consumerUserId: job.consumerUserId,
586
603
  text: job.text,
@@ -588,8 +605,17 @@ export const dispatchDuePushJobs = mutation({
588
605
  pushJobId: String(job._id),
589
606
  runKey,
590
607
  pushMode: "scheduled",
608
+ conversationTargetSource: conversationTarget.source,
609
+ ...(conversationTarget.telegramChatId
610
+ ? { telegramChatId: conversationTarget.telegramChatId }
611
+ : {}),
612
+ ...(conversationTarget.telegramUserId
613
+ ? { telegramUserId: conversationTarget.telegramUserId }
614
+ : {}),
591
615
  },
592
616
  scheduledFor: nowMs,
617
+ provider: conversationTarget.source === "telegram_chat" ? "telegram" : "system_push",
618
+ providerUserId: targetProviderUserId,
593
619
  providerConfig: args.providerConfig,
594
620
  });
595
621
  await ctx.db.insert("messagePushDispatches", {
@@ -688,6 +714,8 @@ export const sendBroadcastToAllActiveAgents = mutation({
688
714
  companyId: args.companyId,
689
715
  },
690
716
  scheduledFor: nowMs,
717
+ provider: "system_push",
718
+ providerUserId: targetConsumerUserId,
691
719
  providerConfig: args.providerConfig,
692
720
  });
693
721
  await ctx.db.insert("messagePushBroadcastDispatches", {
@@ -775,6 +803,8 @@ async function enqueuePushMessage(
775
803
  text: string;
776
804
  metadata: Record<string, string>;
777
805
  scheduledFor: number;
806
+ provider: string;
807
+ providerUserId: string;
778
808
  providerConfig?: ProviderConfig;
779
809
  },
780
810
  ): Promise<Id<"messageQueue">> {
@@ -782,8 +812,8 @@ async function enqueuePushMessage(
782
812
  conversationId: input.conversationId,
783
813
  agentKey: input.agentKey,
784
814
  payload: {
785
- provider: "system_push",
786
- providerUserId: input.consumerUserId,
815
+ provider: input.provider,
816
+ providerUserId: input.providerUserId,
787
817
  messageText: input.text,
788
818
  metadata: input.metadata,
789
819
  },
@@ -812,6 +842,36 @@ async function resolveActiveAgentKeyForUser(ctx: MutationCtx, consumerUserId: st
812
842
  return binding.agentKey;
813
843
  }
814
844
 
845
+ async function resolveConversationTargetForUser(
846
+ ctx: MutationCtx,
847
+ consumerUserId: string,
848
+ ): Promise<{
849
+ conversationId: string;
850
+ source: "telegram_chat" | "legacy_user";
851
+ telegramChatId?: string;
852
+ telegramUserId?: string;
853
+ }> {
854
+ const binding = await ctx.db
855
+ .query("identityBindings")
856
+ .withIndex("by_consumerUserId_and_status", (q) =>
857
+ q.eq("consumerUserId", consumerUserId).eq("status", "active"),
858
+ )
859
+ .first();
860
+ const telegramChatId = binding?.telegramChatId?.trim();
861
+ if (telegramChatId && telegramChatId.length > 0) {
862
+ return {
863
+ conversationId: `telegram:${telegramChatId}`,
864
+ source: "telegram_chat",
865
+ telegramChatId,
866
+ telegramUserId: binding?.telegramUserId?.trim() || undefined,
867
+ };
868
+ }
869
+ return {
870
+ conversationId: `user:${consumerUserId}`,
871
+ source: "legacy_user",
872
+ };
873
+ }
874
+
815
875
  async function advanceJobNextRun(
816
876
  ctx: MutationCtx,
817
877
  job: {
@@ -1 +0,0 @@
1
- //# sourceMappingURL=_ignore.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_ignore.d.ts","sourceRoot":"","sources":["../../../src/client/_generated/_ignore.ts"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- "use strict";
2
- // This is only here so convex-test can detect a _generated folder
3
- //# sourceMappingURL=_ignore.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_ignore.js","sourceRoot":"","sources":["../../../src/client/_generated/_ignore.ts"],"names":[],"mappings":";AAAA,kEAAkE"}
@@ -1,65 +0,0 @@
1
- export type HydratedBridgeRuntimeConfig = {
2
- baseUrl: string | null;
3
- appBaseUrlMapJson: string | null;
4
- serviceId: string | null;
5
- appKey: string | null;
6
- serviceKey: string | null;
7
- serviceKeySecretRef: string | null;
8
- };
9
- export type ResolvedBridgeRuntimeConfig = {
10
- baseUrl: string;
11
- serviceId: string;
12
- appKey: string;
13
- serviceKey: string;
14
- };
15
- export type BridgeExecutionResult = {
16
- success: boolean;
17
- status: number;
18
- functionKey: string;
19
- result?: unknown;
20
- error?: string;
21
- };
22
- type ExecuteBridgeFunctionArgs = {
23
- config: ResolvedBridgeRuntimeConfig;
24
- functionKey: string;
25
- args: Record<string, unknown>;
26
- userToken?: string | null;
27
- auditHeaders?: Record<string, string | undefined>;
28
- fetchImpl?: typeof fetch;
29
- retry?: {
30
- maxAttempts?: number;
31
- baseDelayMs?: number;
32
- };
33
- };
34
- type MaybeExecuteBridgeToolCallArgs = {
35
- toolName: string;
36
- toolArgs: Record<string, unknown>;
37
- hydratedConfig: HydratedBridgeRuntimeConfig | null;
38
- userToken?: string | null;
39
- fetchImpl?: typeof fetch;
40
- retry?: {
41
- maxAttempts?: number;
42
- baseDelayMs?: number;
43
- };
44
- env?: Record<string, string | undefined>;
45
- };
46
- type MaybeExecuteBridgeToolCallResult = {
47
- handled: false;
48
- } | {
49
- handled: true;
50
- functionKey: string;
51
- response: BridgeExecutionResult;
52
- };
53
- export declare function resolveBridgeRuntimeConfig(hydratedConfig: HydratedBridgeRuntimeConfig | null | undefined, env?: Record<string, string | undefined>): {
54
- ok: true;
55
- config: ResolvedBridgeRuntimeConfig;
56
- } | {
57
- ok: false;
58
- error: string;
59
- };
60
- export declare function isBridgeToolName(toolName: string): boolean;
61
- export declare function bridgeFunctionKeyFromToolName(toolName: string): string | null;
62
- export declare function executeBridgeFunction(input: ExecuteBridgeFunctionArgs): Promise<BridgeExecutionResult>;
63
- export declare function maybeExecuteBridgeToolCall(input: MaybeExecuteBridgeToolCallArgs): Promise<MaybeExecuteBridgeToolCallResult>;
64
- export {};
65
- //# sourceMappingURL=bridge.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/client/bridge.ts"],"names":[],"mappings":"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"}
@@ -1,192 +0,0 @@
1
- const BRIDGE_ENV_KEYS = {
2
- baseUrl: ["OPENCLAW_AGENT_BRIDGE_BASE_URL", "AGENT_BRIDGE_BASE_URL"],
3
- serviceId: ["OPENCLAW_SERVICE_ID", "AGENT_BRIDGE_SERVICE_ID"],
4
- serviceKey: ["OPENCLAW_SERVICE_KEY", "AGENT_BRIDGE_SERVICE_KEY"],
5
- appKey: ["OPENCLAW_AGENT_APP", "OPENCLAW_APP_KEY", "AGENT_BRIDGE_APP_KEY"],
6
- };
7
- export function resolveBridgeRuntimeConfig(hydratedConfig, env = process.env) {
8
- const appKey = pickValue(hydratedConfig?.appKey, readEnv(env, BRIDGE_ENV_KEYS.appKey));
9
- const baseUrl = pickValue(hydratedConfig?.baseUrl, readEnv(env, BRIDGE_ENV_KEYS.baseUrl), resolveBaseUrlFromMap(hydratedConfig?.appBaseUrlMapJson, appKey));
10
- const serviceId = pickValue(hydratedConfig?.serviceId, readEnv(env, BRIDGE_ENV_KEYS.serviceId));
11
- const serviceKey = pickValue(hydratedConfig?.serviceKey, readEnv(env, BRIDGE_ENV_KEYS.serviceKey));
12
- const missing = [];
13
- if (!baseUrl)
14
- missing.push("baseUrl");
15
- if (!serviceId)
16
- missing.push("serviceId");
17
- if (!serviceKey)
18
- missing.push("serviceKey");
19
- if (!appKey)
20
- missing.push("appKey");
21
- if (missing.length > 0) {
22
- return {
23
- ok: false,
24
- error: `Agent Bridge config incompleta: ${missing.join(", ")}`,
25
- };
26
- }
27
- const resolvedBaseUrl = baseUrl;
28
- const resolvedServiceId = serviceId;
29
- const resolvedServiceKey = serviceKey;
30
- const resolvedAppKey = appKey;
31
- return {
32
- ok: true,
33
- config: {
34
- baseUrl: normalizeBaseUrl(resolvedBaseUrl),
35
- serviceId: resolvedServiceId,
36
- serviceKey: resolvedServiceKey,
37
- appKey: resolvedAppKey,
38
- },
39
- };
40
- }
41
- export function isBridgeToolName(toolName) {
42
- return /^bridge\.[A-Za-z0-9._-]+$/.test(toolName);
43
- }
44
- export function bridgeFunctionKeyFromToolName(toolName) {
45
- if (!isBridgeToolName(toolName)) {
46
- return null;
47
- }
48
- return toolName.slice("bridge.".length);
49
- }
50
- export async function executeBridgeFunction(input) {
51
- const fetchImpl = input.fetchImpl ?? fetch;
52
- const maxAttempts = Math.max(1, input.retry?.maxAttempts ?? 3);
53
- const baseDelayMs = Math.max(50, input.retry?.baseDelayMs ?? 250);
54
- for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
55
- const response = await fetchImpl(`${input.config.baseUrl}/agent/execute`, {
56
- method: "POST",
57
- headers: {
58
- "Content-Type": "application/json",
59
- "X-Agent-Service-Id": input.config.serviceId,
60
- "X-Agent-Service-Key": input.config.serviceKey,
61
- "X-Agent-App": input.config.appKey,
62
- ...(input.userToken ? { Authorization: `Bearer ${input.userToken}` } : {}),
63
- ...sanitizeHeaderValues(input.auditHeaders),
64
- },
65
- body: JSON.stringify({
66
- functionKey: input.functionKey,
67
- args: input.args,
68
- }),
69
- });
70
- const body = await safeParseJson(response);
71
- const executionResult = {
72
- success: response.ok && body?.success === true,
73
- status: response.status,
74
- functionKey: input.functionKey,
75
- result: body?.result,
76
- error: body?.error ?? (response.ok ? undefined : `HTTP ${response.status}`),
77
- };
78
- if (!shouldRetry(response.status) || attempt >= maxAttempts) {
79
- return executionResult;
80
- }
81
- const backoff = baseDelayMs * 2 ** (attempt - 1);
82
- await sleep(backoff);
83
- }
84
- return {
85
- success: false,
86
- status: 500,
87
- functionKey: input.functionKey,
88
- error: "Bridge execution failed without response",
89
- };
90
- }
91
- export async function maybeExecuteBridgeToolCall(input) {
92
- const functionKey = bridgeFunctionKeyFromToolName(input.toolName);
93
- if (!functionKey) {
94
- return { handled: false };
95
- }
96
- const resolved = resolveBridgeRuntimeConfig(input.hydratedConfig, input.env);
97
- if (!resolved.ok) {
98
- return {
99
- handled: true,
100
- functionKey,
101
- response: {
102
- success: false,
103
- status: 400,
104
- functionKey,
105
- error: resolved.error,
106
- },
107
- };
108
- }
109
- const response = await executeBridgeFunction({
110
- config: resolved.config,
111
- functionKey,
112
- args: input.toolArgs,
113
- userToken: input.userToken,
114
- fetchImpl: input.fetchImpl,
115
- retry: input.retry,
116
- });
117
- return {
118
- handled: true,
119
- functionKey,
120
- response,
121
- };
122
- }
123
- function readEnv(env, keys) {
124
- for (const key of keys) {
125
- const value = env[key];
126
- if (value && value.trim().length > 0) {
127
- return value.trim();
128
- }
129
- }
130
- return null;
131
- }
132
- function pickValue(...values) {
133
- for (const value of values) {
134
- if (value && value.trim().length > 0) {
135
- return value.trim();
136
- }
137
- }
138
- return null;
139
- }
140
- function resolveBaseUrlFromMap(appBaseUrlMapJson, appKey) {
141
- if (!appBaseUrlMapJson || !appKey) {
142
- return null;
143
- }
144
- try {
145
- const parsed = JSON.parse(appBaseUrlMapJson);
146
- const value = parsed?.[appKey];
147
- if (typeof value === "string" && value.trim().length > 0) {
148
- return value.trim();
149
- }
150
- return null;
151
- }
152
- catch {
153
- return null;
154
- }
155
- }
156
- function normalizeBaseUrl(baseUrl) {
157
- return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
158
- }
159
- function shouldRetry(status) {
160
- return status === 429 || status >= 500;
161
- }
162
- function sleep(ms) {
163
- return new Promise((resolve) => {
164
- setTimeout(resolve, ms);
165
- });
166
- }
167
- async function safeParseJson(response) {
168
- const contentType = response.headers.get("content-type");
169
- if (!contentType?.toLowerCase().includes("application/json")) {
170
- return null;
171
- }
172
- try {
173
- return (await response.json());
174
- }
175
- catch {
176
- return null;
177
- }
178
- }
179
- function sanitizeHeaderValues(headers) {
180
- if (!headers) {
181
- return {};
182
- }
183
- const output = {};
184
- for (const [key, value] of Object.entries(headers)) {
185
- if (!value || value.trim().length === 0) {
186
- continue;
187
- }
188
- output[key] = value;
189
- }
190
- return output;
191
- }
192
- //# sourceMappingURL=bridge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/client/bridge.ts"],"names":[],"mappings":"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"}