zeitlich 0.2.49 → 0.2.50

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 (123) hide show
  1. package/README.md +26 -23
  2. package/dist/{activities-zG_FBoY2.d.ts → activities-IuOIvPHO.d.ts} +6 -6
  3. package/dist/{activities-7OcT_vdR.d.cts → activities-cIlq1y1y.d.cts} +6 -6
  4. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  5. package/dist/adapters/sandbox/daytona/index.d.cts +3 -3
  6. package/dist/adapters/sandbox/daytona/index.d.ts +3 -3
  7. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  8. package/dist/adapters/sandbox/daytona/workflow.d.cts +2 -2
  9. package/dist/adapters/sandbox/daytona/workflow.d.ts +2 -2
  10. package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
  11. package/dist/adapters/sandbox/e2b/index.d.cts +1 -1
  12. package/dist/adapters/sandbox/e2b/index.d.ts +1 -1
  13. package/dist/adapters/sandbox/e2b/index.js.map +1 -1
  14. package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
  15. package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
  16. package/dist/adapters/thread/anthropic/index.cjs +45 -42
  17. package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
  18. package/dist/adapters/thread/anthropic/index.d.cts +10 -10
  19. package/dist/adapters/thread/anthropic/index.d.ts +10 -10
  20. package/dist/adapters/thread/anthropic/index.js +45 -42
  21. package/dist/adapters/thread/anthropic/index.js.map +1 -1
  22. package/dist/adapters/thread/anthropic/workflow.d.cts +7 -7
  23. package/dist/adapters/thread/anthropic/workflow.d.ts +7 -7
  24. package/dist/adapters/thread/google-genai/index.cjs +117 -54
  25. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  26. package/dist/adapters/thread/google-genai/index.d.cts +27 -23
  27. package/dist/adapters/thread/google-genai/index.d.ts +27 -23
  28. package/dist/adapters/thread/google-genai/index.js +117 -54
  29. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  30. package/dist/adapters/thread/google-genai/workflow.d.cts +8 -8
  31. package/dist/adapters/thread/google-genai/workflow.d.ts +8 -8
  32. package/dist/adapters/thread/langchain/index.cjs +45 -42
  33. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  34. package/dist/adapters/thread/langchain/index.d.cts +10 -10
  35. package/dist/adapters/thread/langchain/index.d.ts +10 -10
  36. package/dist/adapters/thread/langchain/index.js +45 -42
  37. package/dist/adapters/thread/langchain/index.js.map +1 -1
  38. package/dist/adapters/thread/langchain/workflow.d.cts +7 -7
  39. package/dist/adapters/thread/langchain/workflow.d.ts +7 -7
  40. package/dist/{cold-store-CkWoNtMh.d.cts → cold-store-C0uvYTSi.d.cts} +1 -1
  41. package/dist/{cold-store-DKMAO1Dd.d.ts → cold-store-CCnZYWjx.d.ts} +1 -1
  42. package/dist/index.cjs +15050 -420
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.cts +79 -83
  45. package/dist/index.d.ts +79 -83
  46. package/dist/index.js +15051 -417
  47. package/dist/index.js.map +1 -1
  48. package/dist/{proxy-B7CWEV-T.d.cts → proxy-BVznA2_p.d.cts} +1 -1
  49. package/dist/{proxy-ByFHMVRX.d.ts → proxy-C4J1pNUk.d.ts} +1 -1
  50. package/dist/{thread-manager-Cibe0X5m.d.cts → thread-manager-BqjzWsP7.d.ts} +4 -4
  51. package/dist/{thread-manager-B9rtMEVn.d.cts → thread-manager-CzIs47uG.d.cts} +4 -4
  52. package/dist/{thread-manager-nK-WcFzM.d.ts → thread-manager-Dzl1fHhV.d.cts} +4 -4
  53. package/dist/{thread-manager-7AW4rhfu.d.ts → thread-manager-SkSWRPRc.d.ts} +4 -4
  54. package/dist/{types-gVa5XCWD.d.ts → types-BQvXWcft.d.ts} +1 -1
  55. package/dist/{types-DO4Tkwxo.d.ts → types-CbPnU4RM.d.ts} +3 -3
  56. package/dist/{types-CJ7tCdl6.d.ts → types-D8W5TnSa.d.cts} +3 -3
  57. package/dist/{types-CJ7tCdl6.d.cts → types-D8W5TnSa.d.ts} +3 -3
  58. package/dist/{types-DeVNWqlb.d.ts → types-DZnUqCAP.d.cts} +709 -709
  59. package/dist/{types-CjY93AWZ.d.cts → types-OEN1xrFg.d.cts} +1 -1
  60. package/dist/{types-XUUFvrJ9.d.cts → types-YNesmGKV.d.ts} +709 -709
  61. package/dist/{types-BR-k7h0e.d.cts → types-d2RvEP6v.d.cts} +3 -3
  62. package/dist/{workflow-uhOIj9D-.d.ts → workflow-B3oTe2_D.d.cts} +34 -3
  63. package/dist/{workflow-KbGsxpfh.d.cts → workflow-Bkzg0cjB.d.ts} +34 -3
  64. package/dist/workflow.cjs +15008 -377
  65. package/dist/workflow.cjs.map +1 -1
  66. package/dist/workflow.d.cts +3 -3
  67. package/dist/workflow.d.ts +3 -3
  68. package/dist/workflow.js +15009 -374
  69. package/dist/workflow.js.map +1 -1
  70. package/package.json +10 -37
  71. package/src/adapters/thread/anthropic/activities.ts +1 -1
  72. package/src/adapters/thread/anthropic/fork-transform.test.ts +17 -11
  73. package/src/adapters/thread/anthropic/model-invoker.test.ts +4 -3
  74. package/src/adapters/thread/anthropic/model-invoker.ts +1 -1
  75. package/src/adapters/thread/anthropic/thread-manager.test.ts +2 -2
  76. package/src/adapters/thread/anthropic/thread-manager.ts +1 -1
  77. package/src/adapters/thread/google-genai/activities.ts +1 -1
  78. package/src/adapters/thread/google-genai/fork-transform.test.ts +17 -11
  79. package/src/adapters/thread/google-genai/model-invoker.test.ts +337 -0
  80. package/src/adapters/thread/google-genai/model-invoker.ts +107 -23
  81. package/src/adapters/thread/google-genai/thread-manager.test.ts +2 -2
  82. package/src/adapters/thread/google-genai/thread-manager.ts +1 -1
  83. package/src/adapters/thread/langchain/activities.ts +1 -1
  84. package/src/adapters/thread/langchain/fork-transform.test.ts +17 -11
  85. package/src/adapters/thread/langchain/model-invoker.ts +1 -1
  86. package/src/adapters/thread/langchain/thread-manager.test.ts +2 -2
  87. package/src/adapters/thread/langchain/thread-manager.ts +1 -1
  88. package/src/index.ts +2 -2
  89. package/src/lib/sandbox/capability-types.test.ts +2 -2
  90. package/src/lib/sandbox/manager.ts +2 -6
  91. package/src/lib/sandbox/sandbox.test.ts +1 -1
  92. package/src/lib/sandbox/types.ts +2 -2
  93. package/src/lib/session/session.integration.test.ts +92 -0
  94. package/src/lib/session/session.ts +23 -11
  95. package/src/lib/thread/keys.test.ts +9 -9
  96. package/src/lib/thread/keys.ts +1 -1
  97. package/src/lib/thread/manager.test.ts +24 -14
  98. package/src/lib/thread/manager.ts +19 -23
  99. package/src/lib/thread/snapshot.test.ts +51 -43
  100. package/src/lib/thread/snapshot.ts +54 -32
  101. package/src/lib/thread/test-utils.ts +106 -59
  102. package/src/lib/thread/tiered.test.ts +1 -1
  103. package/src/lib/thread/types.ts +2 -2
  104. package/src/lib/tool-router/router.integration.test.ts +44 -0
  105. package/src/lib/tool-router/router.ts +140 -32
  106. package/src/lib/workflow.ts +49 -0
  107. package/src/{adapters/sandbox/inmemory/proxy.ts → test-utils/in-memory-sandbox-proxy.ts} +5 -16
  108. package/src/{adapters/sandbox/inmemory/index.ts → test-utils/in-memory-sandbox.ts} +11 -3
  109. package/src/tools/bash/bash.test.ts +1 -1
  110. package/src/tools/edit/handler.test.ts +1 -1
  111. package/tsup.config.ts +2 -4
  112. package/dist/adapters/sandbox/inmemory/index.cjs +0 -214
  113. package/dist/adapters/sandbox/inmemory/index.cjs.map +0 -1
  114. package/dist/adapters/sandbox/inmemory/index.d.cts +0 -40
  115. package/dist/adapters/sandbox/inmemory/index.d.ts +0 -40
  116. package/dist/adapters/sandbox/inmemory/index.js +0 -211
  117. package/dist/adapters/sandbox/inmemory/index.js.map +0 -1
  118. package/dist/adapters/sandbox/inmemory/workflow.cjs +0 -36
  119. package/dist/adapters/sandbox/inmemory/workflow.cjs.map +0 -1
  120. package/dist/adapters/sandbox/inmemory/workflow.d.cts +0 -27
  121. package/dist/adapters/sandbox/inmemory/workflow.d.ts +0 -27
  122. package/dist/adapters/sandbox/inmemory/workflow.js +0 -34
  123. package/dist/adapters/sandbox/inmemory/workflow.js.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { randomBytes } from 'crypto';
1
2
  import { Context } from '@temporalio/activity';
2
3
 
3
4
  // src/adapters/thread/google-genai/adapter-id.ts
@@ -53,11 +54,11 @@ function createThreadManager(config) {
53
54
  return {
54
55
  async initialize() {
55
56
  await redis.del(redisKey);
56
- await redis.set(metaKey, "1", "EX", ttlSeconds);
57
+ await redis.set(metaKey, "1", { EX: ttlSeconds });
57
58
  },
58
59
  async load() {
59
60
  await assertThreadExists();
60
- const data = await redis.lrange(redisKey, 0, -1);
61
+ const data = await redis.lRange(redisKey, 0, -1);
61
62
  return data.map(deserialize);
62
63
  },
63
64
  async append(messages) {
@@ -65,22 +66,18 @@ function createThreadManager(config) {
65
66
  await assertThreadExists();
66
67
  if (idOf) {
67
68
  const dedupId = messages.map(idOf).join(":");
68
- await redis.eval(
69
- APPEND_IDEMPOTENT_SCRIPT,
70
- 2,
71
- dedupKey(dedupId),
72
- redisKey,
73
- String(ttlSeconds),
74
- ...messages.map(serialize)
75
- );
69
+ await redis.eval(APPEND_IDEMPOTENT_SCRIPT, {
70
+ keys: [dedupKey(dedupId), redisKey],
71
+ arguments: [String(ttlSeconds), ...messages.map(serialize)]
72
+ });
76
73
  } else {
77
- await redis.rpush(redisKey, ...messages.map(serialize));
74
+ await redis.rPush(redisKey, messages.map(serialize));
78
75
  await redis.expire(redisKey, ttlSeconds);
79
76
  }
80
77
  },
81
78
  async fork(newThreadId) {
82
79
  await assertThreadExists();
83
- const data = await redis.lrange(redisKey, 0, -1);
80
+ const data = await redis.lRange(redisKey, 0, -1);
84
81
  const stateRaw = await redis.get(stateKey);
85
82
  const forked = createThreadManager({
86
83
  ...config,
@@ -89,12 +86,12 @@ function createThreadManager(config) {
89
86
  await forked.initialize();
90
87
  if (data.length > 0) {
91
88
  const newKey = getThreadListKey(key, newThreadId);
92
- await redis.rpush(newKey, ...data);
89
+ await redis.rPush(newKey, data);
93
90
  await redis.expire(newKey, ttlSeconds);
94
91
  }
95
92
  if (stateRaw != null) {
96
93
  const newStateKey = getThreadStateKey(key, newThreadId);
97
- await redis.set(newStateKey, stateRaw, "EX", ttlSeconds);
94
+ await redis.set(newStateKey, stateRaw, { EX: ttlSeconds });
98
95
  }
99
96
  return forked;
100
97
  },
@@ -105,20 +102,20 @@ function createThreadManager(config) {
105
102
  "replaceAll requires the thread manager to be configured with `idOf`"
106
103
  );
107
104
  }
108
- const existing = await redis.lrange(redisKey, 0, -1);
105
+ const existing = await redis.lRange(redisKey, 0, -1);
109
106
  const existingIds = existing.map((raw) => idOf(deserialize(raw))).filter((id) => typeof id === "string");
110
107
  await redis.del(redisKey);
111
108
  if (existingIds.length > 0) {
112
- await redis.del(...existingIds.map(dedupKey));
109
+ await redis.del(existingIds.map(dedupKey));
113
110
  }
114
111
  if (messages.length > 0) {
115
- await redis.rpush(redisKey, ...messages.map(serialize));
112
+ await redis.rPush(redisKey, messages.map(serialize));
116
113
  await redis.expire(redisKey, ttlSeconds);
117
114
  }
118
115
  await redis.expire(metaKey, ttlSeconds);
119
116
  },
120
117
  async delete() {
121
- await redis.del(redisKey, metaKey, stateKey);
118
+ await redis.del([redisKey, metaKey, stateKey]);
122
119
  },
123
120
  async loadState() {
124
121
  const raw = await redis.get(stateKey);
@@ -127,14 +124,14 @@ function createThreadManager(config) {
127
124
  },
128
125
  async saveState(state) {
129
126
  await assertThreadExists();
130
- await redis.set(stateKey, JSON.stringify(state), "EX", ttlSeconds);
127
+ await redis.set(stateKey, JSON.stringify(state), { EX: ttlSeconds });
131
128
  },
132
129
  async deleteState() {
133
130
  await redis.del(stateKey);
134
131
  },
135
132
  async length() {
136
133
  await assertThreadExists();
137
- return redis.llen(redisKey);
134
+ return redis.lLen(redisKey);
138
135
  },
139
136
  async truncateFromId(messageId) {
140
137
  await assertThreadExists();
@@ -143,7 +140,7 @@ function createThreadManager(config) {
143
140
  "truncateFromId requires the thread manager to be configured with `idOf`"
144
141
  );
145
142
  }
146
- const data = await redis.lrange(redisKey, 0, -1);
143
+ const data = await redis.lRange(redisKey, 0, -1);
147
144
  let idx = -1;
148
145
  const removedIds = [];
149
146
  for (let i = 0; i < data.length; i++) {
@@ -158,11 +155,11 @@ function createThreadManager(config) {
158
155
  await redis.del(redisKey);
159
156
  await redis.expire(metaKey, ttlSeconds);
160
157
  } else {
161
- await redis.ltrim(redisKey, 0, idx - 1);
158
+ await redis.lTrim(redisKey, 0, idx - 1);
162
159
  await redis.expire(redisKey, ttlSeconds);
163
160
  }
164
161
  if (removedIds.length > 0) {
165
- await redis.del(...removedIds.map(dedupKey));
162
+ await redis.del(removedIds.map(dedupKey));
166
163
  }
167
164
  }
168
165
  };
@@ -177,7 +174,7 @@ async function encodeSnapshot(config) {
177
174
  }
178
175
  const listKey = getThreadListKey(threadKey, threadId);
179
176
  const stateKey = getThreadStateKey(threadKey, threadId);
180
- const messages = await redis.lrange(listKey, 0, -1);
177
+ const messages = await redis.lRange(listKey, 0, -1);
181
178
  const stateRaw = await redis.get(stateKey);
182
179
  const state = stateRaw == null ? null : JSON.parse(stateRaw);
183
180
  const dedupIds = idOf ? messages.map(idOf) : [];
@@ -197,31 +194,38 @@ async function applySnapshot(config) {
197
194
  }
198
195
  const listKey = getThreadListKey(threadKey, threadId);
199
196
  const stateKey = getThreadStateKey(threadKey, threadId);
200
- await redis.del(listKey, stateKey);
201
- const pipeline = redis.pipeline();
197
+ await redis.del([listKey, stateKey]);
198
+ const pipeline = redis.multi();
202
199
  if (snapshot.messages.length > 0) {
203
- pipeline.rpush(listKey, ...snapshot.messages);
200
+ pipeline.rPush(listKey, snapshot.messages);
204
201
  pipeline.expire(listKey, ttlSeconds);
205
202
  }
206
203
  if (snapshot.state != null) {
207
- pipeline.set(stateKey, JSON.stringify(snapshot.state), "EX", ttlSeconds);
204
+ pipeline.set(stateKey, JSON.stringify(snapshot.state), { EX: ttlSeconds });
208
205
  }
209
206
  for (const id of snapshot.dedupIds) {
210
- pipeline.set(getThreadDedupKey(threadId, id), "1", "EX", ttlSeconds);
207
+ pipeline.set(getThreadDedupKey(threadId, id), "1", { EX: ttlSeconds });
211
208
  }
212
- const results = await pipeline.exec();
213
- if (results) {
214
- const firstErr = results.find(([err]) => err)?.[0] ?? null;
215
- if (firstErr) {
216
- await redis.del(
217
- listKey,
218
- stateKey,
219
- ...snapshot.dedupIds.map((id) => getThreadDedupKey(threadId, id))
220
- ).catch(() => void 0);
221
- throw firstErr;
222
- }
209
+ try {
210
+ await pipeline.execAsPipeline();
211
+ } catch (err) {
212
+ await redis.del([
213
+ listKey,
214
+ stateKey,
215
+ ...snapshot.dedupIds.map((id) => getThreadDedupKey(threadId, id))
216
+ ]).catch(() => void 0);
217
+ throw firstPipelineError(err);
223
218
  }
224
- await redis.set(metaKey, "1", "EX", ttlSeconds);
219
+ await redis.set(metaKey, "1", { EX: ttlSeconds });
220
+ }
221
+ function firstPipelineError(err) {
222
+ if (err != null && typeof err === "object" && "replies" in err && Array.isArray(err.replies)) {
223
+ const firstErr = err.replies.find(
224
+ (r) => r instanceof Error
225
+ );
226
+ if (firstErr) return firstErr;
227
+ }
228
+ return err;
225
229
  }
226
230
  async function clearHotTier(config) {
227
231
  const { redis, threadKey, threadId, dedupIds = [] } = config;
@@ -231,7 +235,7 @@ async function clearHotTier(config) {
231
235
  getThreadStateKey(threadKey, threadId),
232
236
  ...dedupIds.map((id) => getThreadDedupKey(threadId, id))
233
237
  ];
234
- await redis.del(...keys);
238
+ await redis.del(keys);
235
239
  }
236
240
 
237
241
  // src/lib/thread/tiered.ts
@@ -429,7 +433,9 @@ function createGoogleGenAIModelInvoker({
429
433
  redis,
430
434
  client,
431
435
  model,
432
- hooks
436
+ hooks,
437
+ config: generationConfig,
438
+ cache: cacheConfig
433
439
  }) {
434
440
  return async function invokeGoogleGenAIModel2(config) {
435
441
  const { threadId, threadKey, state, assistantMessageId } = config;
@@ -444,12 +450,57 @@ function createGoogleGenAIModelInvoker({
444
450
  const { contents, systemInstruction } = await thread.prepareForInvocation();
445
451
  const functionDeclarations = toFunctionDeclarations(state.tools);
446
452
  const tools = functionDeclarations.length > 0 ? [{ functionDeclarations }] : void 0;
453
+ const {
454
+ systemInstruction: _si,
455
+ tools: _t,
456
+ abortSignal: _as,
457
+ cachedContent: callerCachedContent,
458
+ toolConfig: callerToolConfig,
459
+ ...callerConfig
460
+ } = generationConfig ?? {};
461
+ let liveContents = contents;
462
+ let cachedContentName;
463
+ let cachedWriteTokens;
464
+ if (cacheConfig && cacheConfig.splitIndex > 0 && contents.length > cacheConfig.splitIndex) {
465
+ liveContents = contents.slice(cacheConfig.splitIndex);
466
+ const ttl = cacheConfig.ttlSeconds ?? 300;
467
+ const cacheRedisKey = `${threadKey ?? "messages"}:gemini-cache:${model}:${cacheConfig.splitIndex}:thread:${threadId}`;
468
+ cachedContentName = await redis.get(cacheRedisKey) ?? void 0;
469
+ if (!cachedContentName) {
470
+ const cacheInstance = await client.caches.create({
471
+ model,
472
+ config: {
473
+ contents: contents.slice(0, cacheConfig.splitIndex),
474
+ ...systemInstruction ? { systemInstruction } : {},
475
+ ...tools ? { tools } : {},
476
+ ...callerToolConfig ? { toolConfig: callerToolConfig } : {},
477
+ ttl: `${ttl}s`,
478
+ abortSignal: signal
479
+ }
480
+ });
481
+ if (!cacheInstance?.name) {
482
+ throw new Error("Gemini cache creation did not return a cache name");
483
+ }
484
+ cachedContentName = cacheInstance.name;
485
+ cachedWriteTokens = cacheInstance.usageMetadata?.totalTokenCount ?? void 0;
486
+ const redisTtl = ttl - 5;
487
+ if (redisTtl > 0) {
488
+ await redis.set(cacheRedisKey, cachedContentName, { EX: redisTtl });
489
+ }
490
+ }
491
+ }
447
492
  const stream = await client.models.generateContentStream({
448
493
  model,
449
- contents,
494
+ contents: liveContents,
450
495
  config: {
451
- ...systemInstruction ? { systemInstruction } : {},
452
- ...tools ? { tools } : {},
496
+ ...callerConfig,
497
+ ...cachedContentName ? { cachedContent: cachedContentName } : {
498
+ ...callerCachedContent ? { cachedContent: callerCachedContent } : {
499
+ ...systemInstruction ? { systemInstruction } : {},
500
+ ...tools ? { tools } : {}
501
+ },
502
+ ...callerToolConfig ? { toolConfig: callerToolConfig } : {}
503
+ },
453
504
  abortSignal: signal
454
505
  }
455
506
  });
@@ -463,19 +514,27 @@ function createGoogleGenAIModelInvoker({
463
514
  if (!lastChunk) {
464
515
  throw new Error("Google GenAI stream ended without producing any chunks");
465
516
  }
517
+ for (const part of allParts) {
518
+ if (part.functionCall && !part.functionCall.id) {
519
+ part.functionCall.id = randomBytes(8).toString("hex");
520
+ }
521
+ }
466
522
  const modelContent = { role: "model", parts: allParts };
467
- const functionCalls = lastChunk.functionCalls ?? [];
468
523
  return {
469
524
  message: modelContent,
470
- rawToolCalls: functionCalls.map((fc) => ({
471
- id: fc.id,
472
- name: fc.name ?? "",
473
- args: fc.args ?? {}
525
+ rawToolCalls: allParts.filter(
526
+ (p) => !!p.functionCall
527
+ ).map((p) => ({
528
+ id: p.functionCall.id,
529
+ name: p.functionCall.name ?? "",
530
+ args: p.functionCall.args ?? {}
474
531
  })),
475
532
  usage: {
476
533
  inputTokens: lastChunk.usageMetadata?.promptTokenCount,
477
534
  outputTokens: lastChunk.usageMetadata?.candidatesTokenCount,
478
- cachedReadTokens: lastChunk.usageMetadata?.cachedContentTokenCount
535
+ cachedWriteTokens,
536
+ cachedReadTokens: lastChunk.usageMetadata?.cachedContentTokenCount,
537
+ reasonTokens: lastChunk.usageMetadata?.thoughtsTokenCount
479
538
  }
480
539
  };
481
540
  };
@@ -485,13 +544,17 @@ async function invokeGoogleGenAIModel({
485
544
  client,
486
545
  model,
487
546
  hooks,
488
- config
547
+ config,
548
+ generationConfig,
549
+ cache
489
550
  }) {
490
551
  const invoker = createGoogleGenAIModelInvoker({
491
552
  redis,
492
553
  client,
493
554
  model,
494
- hooks
555
+ hooks,
556
+ config: generationConfig,
557
+ cache
495
558
  });
496
559
  return invoker(config);
497
560
  }