Compare commits
2 Commits
main
...
fix/gemini
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f3474ae51 | ||
|
|
cb4d0ad5c1 |
@ -28,6 +28,7 @@
|
|||||||
- Heartbeat: resolve Telegram account IDs from config-only tokens; cron tool accepts canonical `jobId` and legacy `id` for job actions. (#516) — thanks @YuriNachos
|
- Heartbeat: resolve Telegram account IDs from config-only tokens; cron tool accepts canonical `jobId` and legacy `id` for job actions. (#516) — thanks @YuriNachos
|
||||||
- Discord: stop provider when gateway reconnects are exhausted and surface errors. (#514) — thanks @joshp123
|
- Discord: stop provider when gateway reconnects are exhausted and surface errors. (#514) — thanks @joshp123
|
||||||
- Agents: strip empty assistant text blocks from session history to avoid Claude API 400s. (#210)
|
- Agents: strip empty assistant text blocks from session history to avoid Claude API 400s. (#210)
|
||||||
|
- Agents: scrub unsupported JSON Schema keywords from tool schemas for Cloud Code Assist API compatibility. (#567) — thanks @erikpr1994
|
||||||
- Auto-reply: preserve block reply ordering with timeout fallback for streaming. (#503) — thanks @joshp123
|
- Auto-reply: preserve block reply ordering with timeout fallback for streaming. (#503) — thanks @joshp123
|
||||||
- Auto-reply: block reply ordering fix (duplicate PR superseded by #503). (#483) — thanks @AbhisekBasu1
|
- Auto-reply: block reply ordering fix (duplicate PR superseded by #503). (#483) — thanks @AbhisekBasu1
|
||||||
- Auto-reply: avoid splitting outbound chunks inside parentheses. (#499) — thanks @philipp-spiess
|
- Auto-reply: avoid splitting outbound chunks inside parentheses. (#499) — thanks @philipp-spiess
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import path from "node:path";
|
|||||||
|
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { createClawdbotCodingTools } from "./pi-tools.js";
|
import { __testing, createClawdbotCodingTools } from "./pi-tools.js";
|
||||||
import { createBrowserTool } from "./tools/browser-tool.js";
|
import { createBrowserTool } from "./tools/browser-tool.js";
|
||||||
|
|
||||||
describe("createClawdbotCodingTools", () => {
|
describe("createClawdbotCodingTools", () => {
|
||||||
@ -64,6 +64,28 @@ describe("createClawdbotCodingTools", () => {
|
|||||||
expect(format?.enum).toEqual(["aria", "ai"]);
|
expect(format?.enum).toEqual(["aria", "ai"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("inlines local $ref before removing unsupported keywords", () => {
|
||||||
|
const cleaned = __testing.cleanToolSchemaForGemini({
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
foo: { $ref: "#/$defs/Foo" },
|
||||||
|
},
|
||||||
|
$defs: {
|
||||||
|
Foo: { type: "string", enum: ["a", "b"] },
|
||||||
|
},
|
||||||
|
}) as {
|
||||||
|
$defs?: unknown;
|
||||||
|
properties?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(cleaned.$defs).toBeUndefined();
|
||||||
|
expect(cleaned.properties).toBeDefined();
|
||||||
|
expect(cleaned.properties?.foo).toMatchObject({
|
||||||
|
type: "string",
|
||||||
|
enum: ["a", "b"],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("preserves action enums in normalized schemas", () => {
|
it("preserves action enums in normalized schemas", () => {
|
||||||
const tools = createClawdbotCodingTools();
|
const tools = createClawdbotCodingTools();
|
||||||
const toolNames = [
|
const toolNames = [
|
||||||
@ -331,4 +353,52 @@ describe("createClawdbotCodingTools", () => {
|
|||||||
expect(tools.some((tool) => tool.name === "Bash")).toBe(true);
|
expect(tools.some((tool) => tool.name === "Bash")).toBe(true);
|
||||||
expect(tools.some((tool) => tool.name === "browser")).toBe(false);
|
expect(tools.some((tool) => tool.name === "browser")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("removes unsupported JSON Schema keywords for Cloud Code Assist API compatibility", () => {
|
||||||
|
const tools = createClawdbotCodingTools();
|
||||||
|
|
||||||
|
// Helper to recursively check schema for unsupported keywords
|
||||||
|
const unsupportedKeywords = new Set([
|
||||||
|
"patternProperties",
|
||||||
|
"additionalProperties",
|
||||||
|
"$schema",
|
||||||
|
"$id",
|
||||||
|
"$ref",
|
||||||
|
"$defs",
|
||||||
|
"definitions",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const findUnsupportedKeywords = (
|
||||||
|
schema: unknown,
|
||||||
|
path: string,
|
||||||
|
): string[] => {
|
||||||
|
const found: string[] = [];
|
||||||
|
if (!schema || typeof schema !== "object") return found;
|
||||||
|
if (Array.isArray(schema)) {
|
||||||
|
schema.forEach((item, i) => {
|
||||||
|
found.push(...findUnsupportedKeywords(item, `${path}[${i}]`));
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(
|
||||||
|
schema as Record<string, unknown>,
|
||||||
|
)) {
|
||||||
|
if (unsupportedKeywords.has(key)) {
|
||||||
|
found.push(`${path}.${key}`);
|
||||||
|
}
|
||||||
|
if (value && typeof value === "object") {
|
||||||
|
found.push(...findUnsupportedKeywords(value, `${path}.${key}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const tool of tools) {
|
||||||
|
const violations = findUnsupportedKeywords(
|
||||||
|
tool.parameters,
|
||||||
|
`${tool.name}.parameters`,
|
||||||
|
);
|
||||||
|
expect(violations).toEqual([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -195,12 +195,122 @@ function tryFlattenLiteralAnyOf(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanSchemaForGemini(schema: unknown): unknown {
|
// Keywords that Cloud Code Assist API rejects (not compliant with their JSON Schema subset)
|
||||||
|
const UNSUPPORTED_SCHEMA_KEYWORDS = new Set([
|
||||||
|
"patternProperties",
|
||||||
|
"additionalProperties",
|
||||||
|
"$schema",
|
||||||
|
"$id",
|
||||||
|
"$ref",
|
||||||
|
"$defs",
|
||||||
|
"definitions",
|
||||||
|
]);
|
||||||
|
|
||||||
|
type SchemaDefs = Map<string, unknown>;
|
||||||
|
|
||||||
|
function extendSchemaDefs(
|
||||||
|
defs: SchemaDefs | undefined,
|
||||||
|
schema: Record<string, unknown>,
|
||||||
|
): SchemaDefs | undefined {
|
||||||
|
const defsEntry =
|
||||||
|
schema.$defs &&
|
||||||
|
typeof schema.$defs === "object" &&
|
||||||
|
!Array.isArray(schema.$defs)
|
||||||
|
? (schema.$defs as Record<string, unknown>)
|
||||||
|
: undefined;
|
||||||
|
const legacyDefsEntry =
|
||||||
|
schema.definitions &&
|
||||||
|
typeof schema.definitions === "object" &&
|
||||||
|
!Array.isArray(schema.definitions)
|
||||||
|
? (schema.definitions as Record<string, unknown>)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!defsEntry && !legacyDefsEntry) return defs;
|
||||||
|
|
||||||
|
const next = defs ? new Map(defs) : new Map<string, unknown>();
|
||||||
|
if (defsEntry) {
|
||||||
|
for (const [key, value] of Object.entries(defsEntry)) next.set(key, value);
|
||||||
|
}
|
||||||
|
if (legacyDefsEntry) {
|
||||||
|
for (const [key, value] of Object.entries(legacyDefsEntry))
|
||||||
|
next.set(key, value);
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeJsonPointerSegment(segment: string): string {
|
||||||
|
return segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryResolveLocalRef(
|
||||||
|
ref: string,
|
||||||
|
defs: SchemaDefs | undefined,
|
||||||
|
): unknown | undefined {
|
||||||
|
if (!defs) return undefined;
|
||||||
|
const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
|
||||||
|
if (!match) return undefined;
|
||||||
|
const name = decodeJsonPointerSegment(match[1] ?? "");
|
||||||
|
if (!name) return undefined;
|
||||||
|
return defs.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanSchemaForGeminiWithDefs(
|
||||||
|
schema: unknown,
|
||||||
|
defs: SchemaDefs | undefined,
|
||||||
|
refStack: Set<string> | undefined,
|
||||||
|
): unknown {
|
||||||
if (!schema || typeof schema !== "object") return schema;
|
if (!schema || typeof schema !== "object") return schema;
|
||||||
if (Array.isArray(schema)) return schema.map(cleanSchemaForGemini);
|
if (Array.isArray(schema)) {
|
||||||
|
return schema.map((item) =>
|
||||||
|
cleanSchemaForGeminiWithDefs(item, defs, refStack),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const obj = schema as Record<string, unknown>;
|
const obj = schema as Record<string, unknown>;
|
||||||
|
const nextDefs = extendSchemaDefs(defs, obj);
|
||||||
|
|
||||||
|
const refValue = typeof obj.$ref === "string" ? obj.$ref : undefined;
|
||||||
|
if (refValue) {
|
||||||
|
if (refStack?.has(refValue)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolved = tryResolveLocalRef(refValue, nextDefs);
|
||||||
|
if (resolved) {
|
||||||
|
const nextRefStack = refStack ? new Set(refStack) : new Set<string>();
|
||||||
|
nextRefStack.add(refValue);
|
||||||
|
|
||||||
|
const cleaned = cleanSchemaForGeminiWithDefs(
|
||||||
|
resolved,
|
||||||
|
nextDefs,
|
||||||
|
nextRefStack,
|
||||||
|
);
|
||||||
|
if (!cleaned || typeof cleaned !== "object" || Array.isArray(cleaned)) {
|
||||||
|
return cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: Record<string, unknown> = {
|
||||||
|
...(cleaned as Record<string, unknown>),
|
||||||
|
};
|
||||||
|
for (const key of ["description", "title", "default", "examples"]) {
|
||||||
|
if (key in obj && obj[key] !== undefined) {
|
||||||
|
result[key] = obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: Record<string, unknown> = {};
|
||||||
|
for (const key of ["description", "title", "default", "examples"]) {
|
||||||
|
if (key in obj && obj[key] !== undefined) {
|
||||||
|
result[key] = obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
|
const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
|
||||||
|
const hasOneOf = "oneOf" in obj && Array.isArray(obj.oneOf);
|
||||||
|
|
||||||
// Try to flatten anyOf of literals to a single enum BEFORE processing
|
// Try to flatten anyOf of literals to a single enum BEFORE processing
|
||||||
// This handles Type.Union([Type.Literal("a"), Type.Literal("b")]) patterns
|
// This handles Type.Union([Type.Literal("a"), Type.Literal("b")]) patterns
|
||||||
@ -221,14 +331,28 @@ function cleanSchemaForGemini(schema: unknown): unknown {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to flatten oneOf of literals similarly
|
||||||
|
if (hasOneOf) {
|
||||||
|
const flattened = tryFlattenLiteralAnyOf(obj.oneOf as unknown[]);
|
||||||
|
if (flattened) {
|
||||||
|
const result: Record<string, unknown> = {
|
||||||
|
type: flattened.type,
|
||||||
|
enum: flattened.enum,
|
||||||
|
};
|
||||||
|
for (const key of ["description", "title", "default", "examples"]) {
|
||||||
|
if (key in obj && obj[key] !== undefined) {
|
||||||
|
result[key] = obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const cleaned: Record<string, unknown> = {};
|
const cleaned: Record<string, unknown> = {};
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(obj)) {
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
// Skip unsupported schema features for Gemini:
|
// Skip keywords that Cloud Code Assist API doesn't support
|
||||||
// - patternProperties: not in OpenAPI 3.0 subset
|
if (UNSUPPORTED_SCHEMA_KEYWORDS.has(key)) {
|
||||||
// - const: convert to enum with single value instead
|
|
||||||
if (key === "patternProperties") {
|
|
||||||
// Gemini doesn't support patternProperties - skip it
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,8 +362,8 @@ function cleanSchemaForGemini(schema: unknown): unknown {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip 'type' if we have 'anyOf' — Gemini doesn't allow both
|
// Skip 'type' if we have 'anyOf' or 'oneOf' — Gemini doesn't allow both
|
||||||
if (key === "type" && hasAnyOf) {
|
if (key === "type" && (hasAnyOf || hasOneOf)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,27 +371,29 @@ function cleanSchemaForGemini(schema: unknown): unknown {
|
|||||||
// Recursively clean nested properties
|
// Recursively clean nested properties
|
||||||
const props = value as Record<string, unknown>;
|
const props = value as Record<string, unknown>;
|
||||||
cleaned[key] = Object.fromEntries(
|
cleaned[key] = Object.fromEntries(
|
||||||
Object.entries(props).map(([k, v]) => [k, cleanSchemaForGemini(v)]),
|
Object.entries(props).map(([k, v]) => [
|
||||||
|
k,
|
||||||
|
cleanSchemaForGeminiWithDefs(v, nextDefs, refStack),
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
} else if (key === "items" && value && typeof value === "object") {
|
} else if (key === "items" && value && typeof value === "object") {
|
||||||
// Recursively clean array items schema
|
// Recursively clean array items schema
|
||||||
cleaned[key] = cleanSchemaForGemini(value);
|
cleaned[key] = cleanSchemaForGeminiWithDefs(value, nextDefs, refStack);
|
||||||
} else if (key === "anyOf" && Array.isArray(value)) {
|
} else if (key === "anyOf" && Array.isArray(value)) {
|
||||||
// Clean each anyOf variant
|
// Clean each anyOf variant
|
||||||
cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
|
cleaned[key] = value.map((variant) =>
|
||||||
|
cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack),
|
||||||
|
);
|
||||||
} else if (key === "oneOf" && Array.isArray(value)) {
|
} else if (key === "oneOf" && Array.isArray(value)) {
|
||||||
// Clean each oneOf variant
|
// Clean each oneOf variant
|
||||||
cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
|
cleaned[key] = value.map((variant) =>
|
||||||
|
cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack),
|
||||||
|
);
|
||||||
} else if (key === "allOf" && Array.isArray(value)) {
|
} else if (key === "allOf" && Array.isArray(value)) {
|
||||||
// Clean each allOf variant
|
// Clean each allOf variant
|
||||||
cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
|
cleaned[key] = value.map((variant) =>
|
||||||
} else if (
|
cleanSchemaForGeminiWithDefs(variant, nextDefs, refStack),
|
||||||
key === "additionalProperties" &&
|
);
|
||||||
value &&
|
|
||||||
typeof value === "object"
|
|
||||||
) {
|
|
||||||
// Recursively clean additionalProperties schema
|
|
||||||
cleaned[key] = cleanSchemaForGemini(value);
|
|
||||||
} else {
|
} else {
|
||||||
cleaned[key] = value;
|
cleaned[key] = value;
|
||||||
}
|
}
|
||||||
@ -276,6 +402,18 @@ function cleanSchemaForGemini(schema: unknown): unknown {
|
|||||||
return cleaned;
|
return cleaned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanSchemaForGemini(schema: unknown): unknown {
|
||||||
|
if (!schema || typeof schema !== "object") return schema;
|
||||||
|
if (Array.isArray(schema)) return schema.map(cleanSchemaForGemini);
|
||||||
|
|
||||||
|
const defs = extendSchemaDefs(undefined, schema as Record<string, unknown>);
|
||||||
|
return cleanSchemaForGeminiWithDefs(schema, defs, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanToolSchemaForGemini(schema: Record<string, unknown>): unknown {
|
||||||
|
return cleanSchemaForGemini(schema);
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeToolParameters(tool: AnyAgentTool): AnyAgentTool {
|
function normalizeToolParameters(tool: AnyAgentTool): AnyAgentTool {
|
||||||
const schema =
|
const schema =
|
||||||
tool.parameters && typeof tool.parameters === "object"
|
tool.parameters && typeof tool.parameters === "object"
|
||||||
@ -613,6 +751,10 @@ function createClawdbotReadTool(base: AnyAgentTool): AnyAgentTool {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const __testing = {
|
||||||
|
cleanToolSchemaForGemini,
|
||||||
|
} as const;
|
||||||
|
|
||||||
export function createClawdbotCodingTools(options?: {
|
export function createClawdbotCodingTools(options?: {
|
||||||
bash?: BashToolDefaults & ProcessToolDefaults;
|
bash?: BashToolDefaults & ProcessToolDefaults;
|
||||||
messageProvider?: string;
|
messageProvider?: string;
|
||||||
|
|||||||
@ -179,14 +179,22 @@ async function ensureDevGatewayConfig(opts: { reset?: boolean }) {
|
|||||||
mode: "local",
|
mode: "local",
|
||||||
bind: "loopback",
|
bind: "loopback",
|
||||||
},
|
},
|
||||||
agent: {
|
agents: {
|
||||||
workspace,
|
defaults: {
|
||||||
skipBootstrap: true,
|
workspace,
|
||||||
},
|
skipBootstrap: true,
|
||||||
identity: {
|
},
|
||||||
name: DEV_IDENTITY_NAME,
|
list: [
|
||||||
theme: DEV_IDENTITY_THEME,
|
{
|
||||||
emoji: DEV_IDENTITY_EMOJI,
|
id: "dev",
|
||||||
|
default: true,
|
||||||
|
identity: {
|
||||||
|
name: DEV_IDENTITY_NAME,
|
||||||
|
theme: DEV_IDENTITY_THEME,
|
||||||
|
emoji: DEV_IDENTITY_EMOJI,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await ensureDevWorkspace(workspace);
|
await ensureDevWorkspace(workspace);
|
||||||
|
|||||||
@ -10,12 +10,6 @@ const DEFAULT_MINIMAX_CONTEXT_WINDOW = 200000;
|
|||||||
const DEFAULT_MINIMAX_MAX_TOKENS = 8192;
|
const DEFAULT_MINIMAX_MAX_TOKENS = 8192;
|
||||||
export const MINIMAX_HOSTED_MODEL_REF = `minimax/${MINIMAX_HOSTED_MODEL_ID}`;
|
export const MINIMAX_HOSTED_MODEL_REF = `minimax/${MINIMAX_HOSTED_MODEL_ID}`;
|
||||||
|
|
||||||
const DEFAULT_MINIMAX_BASE_URL = "https://api.minimax.io/v1";
|
|
||||||
export const MINIMAX_HOSTED_MODEL_ID = "MiniMax-M2.1";
|
|
||||||
const DEFAULT_MINIMAX_CONTEXT_WINDOW = 200000;
|
|
||||||
const DEFAULT_MINIMAX_MAX_TOKENS = 8192;
|
|
||||||
export const MINIMAX_HOSTED_MODEL_REF = `minimax/${MINIMAX_HOSTED_MODEL_ID}`;
|
|
||||||
|
|
||||||
export async function writeOAuthCredentials(
|
export async function writeOAuthCredentials(
|
||||||
provider: OAuthProvider,
|
provider: OAuthProvider,
|
||||||
creds: OAuthCredentials,
|
creds: OAuthCredentials,
|
||||||
@ -176,7 +170,7 @@ export function applyMinimaxHostedProviderConfig(
|
|||||||
cfg: ClawdbotConfig,
|
cfg: ClawdbotConfig,
|
||||||
params?: { baseUrl?: string },
|
params?: { baseUrl?: string },
|
||||||
): ClawdbotConfig {
|
): ClawdbotConfig {
|
||||||
const models = { ...cfg.agent?.models };
|
const models = { ...(cfg.agents?.defaults?.models ?? {}) };
|
||||||
models[MINIMAX_HOSTED_MODEL_REF] = {
|
models[MINIMAX_HOSTED_MODEL_REF] = {
|
||||||
...models[MINIMAX_HOSTED_MODEL_REF],
|
...models[MINIMAX_HOSTED_MODEL_REF],
|
||||||
alias: models[MINIMAX_HOSTED_MODEL_REF]?.alias ?? "Minimax",
|
alias: models[MINIMAX_HOSTED_MODEL_REF]?.alias ?? "Minimax",
|
||||||
@ -212,9 +206,12 @@ export function applyMinimaxHostedProviderConfig(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...cfg,
|
...cfg,
|
||||||
agent: {
|
agents: {
|
||||||
...cfg.agent,
|
...cfg.agents,
|
||||||
models,
|
defaults: {
|
||||||
|
...cfg.agents?.defaults,
|
||||||
|
models,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
models: {
|
models: {
|
||||||
mode: cfg.models?.mode ?? "merge",
|
mode: cfg.models?.mode ?? "merge",
|
||||||
@ -254,17 +251,21 @@ export function applyMinimaxHostedConfig(
|
|||||||
const next = applyMinimaxHostedProviderConfig(cfg, params);
|
const next = applyMinimaxHostedProviderConfig(cfg, params);
|
||||||
return {
|
return {
|
||||||
...next,
|
...next,
|
||||||
agent: {
|
agents: {
|
||||||
...next.agent,
|
...next.agents,
|
||||||
model: {
|
defaults: {
|
||||||
...(next.agent?.model &&
|
...next.agents?.defaults,
|
||||||
"fallbacks" in (next.agent.model as Record<string, unknown>)
|
model: {
|
||||||
? {
|
...(next.agents?.defaults?.model &&
|
||||||
fallbacks: (next.agent.model as { fallbacks?: string[] })
|
"fallbacks" in (next.agents.defaults.model as Record<string, unknown>)
|
||||||
.fallbacks,
|
? {
|
||||||
}
|
fallbacks: (
|
||||||
: undefined),
|
next.agents.defaults.model as { fallbacks?: string[] }
|
||||||
primary: MINIMAX_HOSTED_MODEL_REF,
|
).fallbacks,
|
||||||
|
}
|
||||||
|
: undefined),
|
||||||
|
primary: MINIMAX_HOSTED_MODEL_REF,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -546,7 +546,8 @@ async function promptWhatsAppAllowFrom(
|
|||||||
"WhatsApp number",
|
"WhatsApp number",
|
||||||
);
|
);
|
||||||
const entry = await prompter.text({
|
const entry = await prompter.text({
|
||||||
message: "Your personal WhatsApp number (the phone you will message from)",
|
message:
|
||||||
|
"Your personal WhatsApp number (the phone you will message from)",
|
||||||
placeholder: "+15555550123",
|
placeholder: "+15555550123",
|
||||||
initialValue: existingAllowFrom[0],
|
initialValue: existingAllowFrom[0],
|
||||||
validate: (value) => {
|
validate: (value) => {
|
||||||
@ -613,7 +614,8 @@ async function promptWhatsAppAllowFrom(
|
|||||||
"WhatsApp number",
|
"WhatsApp number",
|
||||||
);
|
);
|
||||||
const entry = await prompter.text({
|
const entry = await prompter.text({
|
||||||
message: "Your personal WhatsApp number (the phone you will message from)",
|
message:
|
||||||
|
"Your personal WhatsApp number (the phone you will message from)",
|
||||||
placeholder: "+15555550123",
|
placeholder: "+15555550123",
|
||||||
initialValue: existingAllowFrom[0],
|
initialValue: existingAllowFrom[0],
|
||||||
validate: (value) => {
|
validate: (value) => {
|
||||||
|
|||||||
@ -1202,13 +1202,14 @@ export type AgentDefaultsConfig = {
|
|||||||
every?: string;
|
every?: string;
|
||||||
/** Heartbeat model override (provider/model). */
|
/** Heartbeat model override (provider/model). */
|
||||||
model?: string;
|
model?: string;
|
||||||
/** Delivery target (last|whatsapp|telegram|discord|signal|imessage|none). */
|
/** Delivery target (last|whatsapp|telegram|discord|slack|msteams|signal|imessage|none). */
|
||||||
target?:
|
target?:
|
||||||
| "last"
|
| "last"
|
||||||
| "whatsapp"
|
| "whatsapp"
|
||||||
| "telegram"
|
| "telegram"
|
||||||
| "discord"
|
| "discord"
|
||||||
| "slack"
|
| "slack"
|
||||||
|
| "msteams"
|
||||||
| "signal"
|
| "signal"
|
||||||
| "imessage"
|
| "imessage"
|
||||||
| "none";
|
| "none";
|
||||||
|
|||||||
@ -601,6 +601,7 @@ const HeartbeatSchema = z
|
|||||||
z.literal("telegram"),
|
z.literal("telegram"),
|
||||||
z.literal("discord"),
|
z.literal("discord"),
|
||||||
z.literal("slack"),
|
z.literal("slack"),
|
||||||
|
z.literal("msteams"),
|
||||||
z.literal("signal"),
|
z.literal("signal"),
|
||||||
z.literal("imessage"),
|
z.literal("imessage"),
|
||||||
z.literal("none"),
|
z.literal("none"),
|
||||||
|
|||||||
@ -55,9 +55,11 @@ export async function monitorMSTeamsProvider(
|
|||||||
const port = msteamsCfg.webhook?.port ?? 3978;
|
const port = msteamsCfg.webhook?.port ?? 3978;
|
||||||
const textLimit = resolveTextChunkLimit(cfg, "msteams");
|
const textLimit = resolveTextChunkLimit(cfg, "msteams");
|
||||||
const MB = 1024 * 1024;
|
const MB = 1024 * 1024;
|
||||||
|
const agentDefaults = cfg.agents?.defaults;
|
||||||
const mediaMaxBytes =
|
const mediaMaxBytes =
|
||||||
typeof cfg.agent?.mediaMaxMb === "number" && cfg.agent.mediaMaxMb > 0
|
typeof agentDefaults?.mediaMaxMb === "number" &&
|
||||||
? Math.floor(cfg.agent.mediaMaxMb * MB)
|
agentDefaults.mediaMaxMb > 0
|
||||||
|
? Math.floor(agentDefaults.mediaMaxMb * MB)
|
||||||
: 8 * MB;
|
: 8 * MB;
|
||||||
const conversationStore =
|
const conversationStore =
|
||||||
opts.conversationStore ?? createMSTeamsConversationStoreFs();
|
opts.conversationStore ?? createMSTeamsConversationStoreFs();
|
||||||
|
|||||||
@ -122,9 +122,7 @@ export async function sendMessageTelegram(
|
|||||||
const client: ApiClientOptions | undefined = fetchImpl
|
const client: ApiClientOptions | undefined = fetchImpl
|
||||||
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
||||||
: undefined;
|
: undefined;
|
||||||
const api =
|
const api = opts.api ?? new Bot(token, client ? { client } : undefined).api;
|
||||||
opts.api ??
|
|
||||||
new Bot(token, client ? { client } : undefined).api;
|
|
||||||
const mediaUrl = opts.mediaUrl?.trim();
|
const mediaUrl = opts.mediaUrl?.trim();
|
||||||
|
|
||||||
// Build optional params for forum topics and reply threading.
|
// Build optional params for forum topics and reply threading.
|
||||||
@ -296,9 +294,7 @@ export async function reactMessageTelegram(
|
|||||||
const client: ApiClientOptions | undefined = fetchImpl
|
const client: ApiClientOptions | undefined = fetchImpl
|
||||||
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
||||||
: undefined;
|
: undefined;
|
||||||
const api =
|
const api = opts.api ?? new Bot(token, client ? { client } : undefined).api;
|
||||||
opts.api ??
|
|
||||||
new Bot(token, client ? { client } : undefined).api;
|
|
||||||
const request = createTelegramRetryRunner({
|
const request = createTelegramRetryRunner({
|
||||||
retry: opts.retry,
|
retry: opts.retry,
|
||||||
configRetry: account.config.retry,
|
configRetry: account.config.retry,
|
||||||
|
|||||||
@ -11,10 +11,7 @@ export async function setTelegramWebhook(opts: {
|
|||||||
const client: ApiClientOptions | undefined = fetchImpl
|
const client: ApiClientOptions | undefined = fetchImpl
|
||||||
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
||||||
: undefined;
|
: undefined;
|
||||||
const bot = new Bot(
|
const bot = new Bot(opts.token, client ? { client } : undefined);
|
||||||
opts.token,
|
|
||||||
client ? { client } : undefined,
|
|
||||||
);
|
|
||||||
await bot.api.setWebhook(opts.url, {
|
await bot.api.setWebhook(opts.url, {
|
||||||
secret_token: opts.secret,
|
secret_token: opts.secret,
|
||||||
drop_pending_updates: opts.dropPendingUpdates ?? false,
|
drop_pending_updates: opts.dropPendingUpdates ?? false,
|
||||||
@ -26,9 +23,6 @@ export async function deleteTelegramWebhook(opts: { token: string }) {
|
|||||||
const client: ApiClientOptions | undefined = fetchImpl
|
const client: ApiClientOptions | undefined = fetchImpl
|
||||||
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
||||||
: undefined;
|
: undefined;
|
||||||
const bot = new Bot(
|
const bot = new Bot(opts.token, client ? { client } : undefined);
|
||||||
opts.token,
|
|
||||||
client ? { client } : undefined,
|
|
||||||
);
|
|
||||||
await bot.api.deleteWebhook();
|
await bot.api.deleteWebhook();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user