Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@ jobs:
- name: Install WebUI dependencies
run: cd web && npm ci

- name: Build SDK workspace
run: npm run build -w packages/sdk

- name: Build
run: npm run build

Expand All @@ -121,8 +118,6 @@ jobs:
with:
context: .
push: false
cache-from: type=gha,scope=teleton-docker
cache-to: type=gha,mode=max,scope=teleton-docker

# ---- Telegram notification (one summary per push, pushes only) ----
notify:
Expand Down
22 changes: 4 additions & 18 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ jobs:

- run: npm ci
- run: cd web && npm ci
- run: npm run build -w packages/sdk
- run: npm run build
- run: node scripts/check-sdk-package.mjs
- run: npm run typecheck
- run: npm run build
- run: node dist/cli/index.js --help

- name: Run tests
Expand All @@ -44,12 +43,7 @@ jobs:
- name: Enforce SDK coverage
run: npm run test:sdk:coverage

- uses: actions/upload-artifact@v7
with:
name: dist
path: dist/

# Verify the image before any registry publication starts.
# Ensure Docker is buildable before publishing immutable npm packages.
verify-docker:
runs-on: ubuntu-latest
timeout-minutes: 30
Expand All @@ -62,8 +56,6 @@ jobs:
with:
context: .
push: false
cache-from: type=gha,scope=teleton-docker
cache-to: type=gha,mode=max,scope=teleton-docker

# ---- Publish to npm ----
publish-npm:
Expand Down Expand Up @@ -102,12 +94,6 @@ jobs:
- run: cd web && npm ci
if: steps.check.outputs.publish == 'true'

- uses: actions/download-artifact@v8
if: steps.check.outputs.publish == 'true'
with:
name: dist
path: dist/

- run: npm publish --provenance --access public
if: steps.check.outputs.publish == 'true'
env:
Expand Down Expand Up @@ -185,8 +171,8 @@ jobs:
with:
context: .
push: true
cache-from: type=gha,scope=teleton-docker
cache-to: type=gha,mode=max,scope=teleton-docker
cache-from: type=registry,ref=ghcr.io/${{ steps.meta.outputs.repo }}:latest
cache-to: type=inline
tags: |
ghcr.io/${{ steps.meta.outputs.repo }}:${{ steps.meta.outputs.version }}
ghcr.io/${{ steps.meta.outputs.repo }}:latest
Expand Down
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.11.2] - 2026-09-06

### Added

- Inline URL and copy buttons inside native Telegram Rich Message paragraphs, including a subtle link style.
- Claude Fable 5.1, GPT-6 Astra, and Gemini 3.8 Flash across their supported native, Codex, and OpenRouter providers.

### Changed

- Simplified CI and release builds by removing redundant SDK and artifact stages and using the published Docker image as the release cache.

### Fixed

- Updated the transitive `fast-uri`, `qs`, and `browserslist` packages to patched versions required by the security audits.

## [0.11.1] - 2026-08-28

### Changed
Expand Down Expand Up @@ -595,7 +610,8 @@ Git history rewritten to fix commit attribution (email update from `tonresistor@
- Professional distribution (npm, Docker, CI/CD)
- Pre-commit hooks and linting infrastructure

[Unreleased]: https://github.com/TONresistor/teleton-agent/compare/v0.11.1...HEAD
[Unreleased]: https://github.com/TONresistor/teleton-agent/compare/v0.11.2...HEAD
[0.11.2]: https://github.com/TONresistor/teleton-agent/compare/v0.11.1...v0.11.2
[0.11.1]: https://github.com/TONresistor/teleton-agent/compare/v0.11.0...v0.11.1
[0.11.0]: https://github.com/TONresistor/teleton-agent/compare/v0.10.1...v0.11.0
[0.10.1]: https://github.com/TONresistor/teleton-agent/compare/v0.10.0...v0.10.1
Expand Down
29 changes: 15 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "teleton",
"version": "0.11.1",
"version": "0.11.2",
"workspaces": [
"packages/*"
],
Expand Down Expand Up @@ -101,7 +101,7 @@
"axios": ">=1.18.1",
"brace-expansion": "5.0.9",
"esbuild": "0.28.1",
"fast-uri": "3.1.5",
"fast-uri": "3.1.6",
"ip-address": "10.3.1",
"nanoid": "3.3.18",
"sharp": "0.35.3"
Expand Down
33 changes: 33 additions & 0 deletions src/agent/__tests__/model-request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,39 @@ describe("model request preparation", () => {
expect(request.options.temperature).toBe(0.4);
});

it.each([
["openai", "gpt-6-astra"],
["openrouter", "anthropic/claude-fable-5.1"],
["openrouter", "openai/gpt-6-astra"],
["openrouter", "google/gemini-3.8-flash"],
])("omits unsupported temperature for %s/%s", (provider, model) => {
const config = AgentConfigSchema.parse({
provider,
model,
api_key: "test-key",
temperature: 0.4,
});
const request = prepareModelRequest(config, { context: { messages: [] } });

expect(request.model.id).toBe(model);
expect(request.options).not.toHaveProperty("temperature");
});

it("enables mandatory adaptive thinking for Claude Fable 5.1", () => {
const config = AgentConfigSchema.parse({
provider: "anthropic",
model: "claude-fable-5-1",
api_key: "test-key",
});
const request = prepareModelRequest(config, { context: { messages: [] } });

expect(request.options.thinkingEnabled).toBe(true);
expect(request.model.compat).toMatchObject({
forceAdaptiveThinking: true,
supportsTemperature: false,
});
});

it("passes the configured reasoning effort to Codex", () => {
const config = AgentConfigSchema.parse({
provider: "codex",
Expand Down
9 changes: 9 additions & 0 deletions src/agent/model-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ const GOOGLE_MODELS_WITHOUT_SAMPLING_PARAMS = new Set([

function modelSupportsTemperature(provider: SupportedProvider, modelId: string): boolean {
if (provider === "codex" || provider === "grok-build") return false;
if (provider === "openai" && modelId === "gpt-6-astra") return false;
if (
provider === "openrouter" &&
["anthropic/claude-fable-5.1", "openai/gpt-6-astra", "google/gemini-3.8-flash"].includes(
modelId
)
)
return false;
if (provider === "google" && GOOGLE_MODELS_WITHOUT_SAMPLING_PARAMS.has(modelId)) return false;
return true;
}
Expand Down Expand Up @@ -128,6 +136,7 @@ export function prepareModelRequest(
signal: request.signal,
timeoutMs: request.timeoutMs,
...getReasoningOptions(provider, config.reasoning_effort),
...(provider === "anthropic" && model.id === "claude-fable-5-1" && { thinkingEnabled: true }),
...getProviderPayloadOptions(provider),
} as ProviderStreamOptions,
};
Expand Down
31 changes: 31 additions & 0 deletions src/agent/tools/telegram/messaging/__tests__/send-message.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,37 @@ describe("telegram_send_message", () => {
});
});

it("sends small buttons inline with text", async () => {
const rich = {
blocks: [
{
type: "inline" as const,
items: [
{ type: "text" as const, text: "Open " },
{
type: "button" as const,
label: "Docs",
action: { type: "url" as const, url: "https://example.com" },
},
],
},
],
};

const result = await telegramSendMessageExecutor({ rich }, context());

expect(result).toMatchObject({ success: true, data: { deliveryKind: "rich" } });
expect((result.data as { renderedText: string }).renderedText).toBe(
'<p>Open <tg-button type="url" url="https://example.com">Docs</tg-button></p>'
);
expect(mocks.sendMessage).toHaveBeenCalledWith({
chatId: "current",
text: "",
replyToId: undefined,
rich,
});
});

it("resolves admin attachment paths before sending", async () => {
const result = await telegramSendMessageExecutor(
{
Expand Down
77 changes: 54 additions & 23 deletions src/agent/tools/telegram/messaging/rich-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,48 @@ const buttonStyleSchema = Type.Union([
Type.Literal("primary"),
Type.Literal("success"),
Type.Literal("danger"),
Type.Literal("link"),
]);

const buttonSchema = Type.Object(
{
label: Type.String({ minLength: 1, maxLength: 256 }),
action: Type.Union([
Type.Object(
{
type: Type.Literal("url"),
url: Type.String({ minLength: 1, maxLength: 2048 }),
},
{ additionalProperties: false }
),
Type.Object(
{
type: Type.Literal("copy"),
text: Type.String({ minLength: 1, maxLength: 256 }),
},
{ additionalProperties: false }
),
]),
style: Type.Optional(buttonStyleSchema),
},
{ additionalProperties: false }
);
const buttonFields = {
label: Type.String({ minLength: 1, maxLength: 256 }),
action: Type.Union([
Type.Object(
{
type: Type.Literal("url"),
url: Type.String({ minLength: 1, maxLength: 2048 }),
},
{ additionalProperties: false }
),
Type.Object(
{
type: Type.Literal("copy"),
text: Type.String({ minLength: 1, maxLength: 256 }),
},
{ additionalProperties: false }
),
]),
style: Type.Optional(buttonStyleSchema),
};

const buttonSchema = Type.Object(buttonFields, { additionalProperties: false });

const inlineItemSchema = Type.Union([
Type.Object(
{
type: Type.Literal("text"),
text: Type.String({ minLength: 1, maxLength: RICH_MESSAGE_MAX_BYTES }),
},
{ additionalProperties: false }
),
Type.Object(
{
type: Type.Literal("button"),
...buttonFields,
},
{ additionalProperties: false }
),
]);

const buttonRowFields = {
align: Type.Optional(
Expand Down Expand Up @@ -76,6 +93,20 @@ const richBlockSchema = Type.Union([
},
{ additionalProperties: false }
),
Type.Object(
{
type: Type.Literal("inline"),
items: Type.Array(inlineItemSchema, {
minItems: 1,
maxItems: RICH_MESSAGE_MAX_BLOCKS,
}),
},
{
additionalProperties: false,
description:
"One paragraph mixing plain text and small inline URL/copy buttons in exact order. Use link style for a subtle text-like button.",
}
),
Type.Object(
{
type: Type.Literal("heading"),
Expand Down
2 changes: 1 addition & 1 deletion src/agent/tools/telegram/messaging/send-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface SendMessageParams {
export const telegramSendMessageTool: Tool = {
name: "telegram_send_message",
description:
"Send a Telegram message. Omit chatId to use the current chat. Use text alone for a normal message, or add rich for one native user-mode Rich Message with structured blocks, local attachments, URL/copy buttons, alignment, and styles. Do not write tg:// references yourself.",
"Send a Telegram message. Omit chatId to use the current chat. Use text alone for a normal message, or add rich for one native user-mode Rich Message with structured blocks, local attachments, small inline or row URL/copy buttons, alignment, and styles. Do not write tg:// references yourself.",
parameters: Type.Object({
chatId: Type.Optional(
Type.String({
Expand Down
Loading